From 9742842795e964c7f260aec831665d5cb28cd420 Mon Sep 17 00:00:00 2001 From: Gabriel Hurley Date: Mon, 31 Oct 2011 11:31:05 -0700 Subject: [PATCH] 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 --- .bzrignore | 16 +- .gitignore | 23 +- README | 34 +- django-openstack/README | 56 - django-openstack/django_openstack/api.py | 1093 --------- .../django_openstack/context_processors.py | 48 - .../django_openstack/dash/urls.py | 118 - .../django_openstack/dash/views/containers.py | 95 - .../django_openstack/dash/views/networks.py | 252 --- .../django_openstack/decorators.py | 42 - .../django_openstack/exceptions.py | 8 - .../locale/es/LC_MESSAGES/django.po | 1948 ---------------- .../locale/fr/LC_MESSAGES/django.po | 1948 ---------------- .../locale/ja/LC_MESSAGES/django.mo | Bin 2564 -> 0 bytes .../locale/pt/LC_MESSAGES/django.po | 1947 ---------------- .../locale/zh-cn/LC_MESSAGES/django.po | 1947 ---------------- .../locale/zh-tw/LC_MESSAGES/django.po | 1947 ---------------- django-openstack/django_openstack/signals.py | 50 - .../django_openstack/syspanel/urls.py | 78 - .../django_openstack/auth/_login.html | 17 - .../common/instances/_reboot.html | 9 - .../common/instances/_terminate.html | 9 - .../django_openstack/dash/_sidebar.html | 28 - .../dash/containers/index.html | 19 - .../dash/networks/detail.html | 31 - .../django_openstack/syspanel/_sidebar.html | 18 - .../syspanel/flavors/index.html | 19 - .../templatetags/sidebar_modules.py | 46 - .../templatetags/templatetags/swift_paging.py | 15 - django-openstack/django_openstack/test.py | 99 - .../django_openstack/tests/api_tests.py | 1587 ------------- .../django_openstack/tests/broken/README | 2 - .../django_openstack/tests/broken/base.py | 81 - .../tests/broken/credential_tests.py | 70 - .../tests/broken/image_tests.py | 237 -- .../tests/broken/instance_tests.py | 69 - .../tests/broken/keypair_tests.py | 93 - .../tests/broken/region_tests.py | 41 - .../tests/broken/test_models.py | 187 -- .../tests/broken/volume_tests.py | 171 -- .../tests/context_processor_tests.py | 23 - .../tests/templatetag_tests.py | 71 - .../django_openstack/tests/view_tests/base.py | 77 - .../tests/view_tests/dash/container_tests.py | 121 - .../tests/view_tests/dash/port_tests.py | 104 - doc/generate_autodoc_index.py | 68 - doc/source/index.rst | 69 - doc/source/testing.rst | 32 - {doc => docs}/Makefile | 0 .../source/_static/.gitignore | 0 {doc => docs}/source/conf.py | 96 +- docs/source/faq.rst | 37 + docs/source/glossary.rst | 19 + docs/source/index.rst | 101 + docs/source/intro.rst | 124 ++ docs/source/quickstart.rst | 146 ++ docs/source/ref/context_processors.rst | 6 + docs/source/ref/decorators.rst | 6 + docs/source/ref/exceptions.rst | 6 + docs/source/ref/forms.rst | 17 + docs/source/ref/horizon.rst | 42 + docs/source/ref/middleware.rst | 6 + docs/source/ref/run_tests.rst | 100 + docs/source/ref/users.rst | 6 + docs/source/ref/views.rst | 12 + docs/source/testing.rst | 62 + {django-openstack => horizon}/LICENSE | 0 {django-openstack => horizon}/Makefile | 4 +- horizon/README | 59 + {django-openstack => horizon}/bootstrap.py | 0 {django-openstack => horizon}/buildout.cfg | 13 +- horizon/horizon/__init__.py | 50 + horizon/horizon/api/__init__.py | 39 + horizon/horizon/api/base.py | 118 + horizon/horizon/api/deprecated.py | 95 + horizon/horizon/api/glance.py | 89 + horizon/horizon/api/keystone.py | 256 +++ horizon/horizon/api/nova.py | 357 +++ horizon/horizon/api/quantum.py | 133 ++ horizon/horizon/api/swift.py | 132 ++ horizon/horizon/base.py | 594 +++++ horizon/horizon/context_processors.py | 69 + .../horizon/dashboards}/__init__.py | 0 .../horizon/dashboards/nova}/__init__.py | 0 .../dashboards/nova/containers}/__init__.py | 0 .../dashboards/nova/containers/forms.py | 119 +- .../dashboards/nova/containers/panel.py | 35 + .../dashboards/nova/containers/tests.py | 177 +- .../dashboards/nova/containers/urls.py | 36 +- .../dashboards/nova/containers/views.py | 134 ++ horizon/horizon/dashboards/nova/dashboard.py | 33 + .../dashboards/nova/floating_ips}/__init__.py | 0 .../dashboards/nova/floating_ips/forms.py | 72 +- .../dashboards/nova/floating_ips/panel.py | 30 + .../dashboards/nova/floating_ips/tests.py | 85 +- .../dashboards/nova/floating_ips/urls.py | 28 + .../dashboards/nova/floating_ips/views.py | 88 + .../dashboards/nova/images}/__init__.py | 0 .../horizon/dashboards/nova/images/forms.py | 142 +- .../horizon/dashboards/nova/images/panel.py | 11 +- .../horizon/dashboards/nova/images/tests.py | 64 +- .../horizon/dashboards/nova/images/urls.py | 27 + .../horizon/dashboards/nova/images/views.py | 163 ++ .../dashboards/nova/instances}/__init__.py | 0 .../dashboards/nova/instances/forms.py | 101 + .../dashboards/nova/instances/panel.py | 30 + .../dashboards/nova/instances/tests.py | 134 +- .../horizon/dashboards/nova/instances/urls.py | 33 + .../dashboards/nova/instances/views.py | 184 +- .../dashboards/nova/keypairs}/__init__.py | 0 .../horizon/dashboards/nova/keypairs/forms.py | 65 +- .../horizon/dashboards/nova/keypairs/panel.py | 30 + .../horizon/dashboards/nova/keypairs/tests.py | 50 +- .../horizon/dashboards/nova/keypairs/urls.py | 28 + .../horizon/dashboards/nova/keypairs/views.py | 80 + .../horizon/dashboards/nova}/models.py | 0 .../dashboards/nova/networks}/__init__.py | 0 .../horizon/dashboards/nova/networks/forms.py | 134 +- .../horizon/dashboards/nova/networks/panel.py | 33 + .../horizon/dashboards/nova/networks/tests.py | 118 +- .../horizon/dashboards/nova/networks/urls.py | 31 + .../horizon/dashboards/nova/networks/views.py | 231 ++ .../dashboards/nova/overview}/__init__.py | 0 .../horizon/dashboards/nova/overview/panel.py | 30 + .../horizon/dashboards/nova/overview}/urls.py | 10 +- .../nova/security_groups}/__init__.py | 0 .../dashboards/nova/security_groups/forms.py | 91 +- .../dashboards/nova/security_groups/panel.py | 30 + .../dashboards/nova/security_groups/tests.py | 113 +- .../dashboards/nova/security_groups/urls.py | 28 + .../dashboards/nova/security_groups/views.py | 103 + .../dashboards/nova/snapshots}/__init__.py | 0 .../dashboards/nova/snapshots/forms.py | 57 + .../dashboards/nova/snapshots/panel.py | 30 + .../dashboards/nova/snapshots/tests.py | 75 +- .../horizon/dashboards/nova/snapshots/urls.py | 26 + .../dashboards/nova/snapshots/views.py | 66 +- .../dashboards/nova/templates/nova}/base.html | 11 +- .../templates/nova}/containers/_delete.html | 0 .../templates/nova}/containers/_form.html | 0 .../templates/nova}/containers/_list.html | 6 +- .../templates/nova}/containers/create.html | 6 +- .../nova/templates/nova/containers/index.html | 19 + .../nova}/floating_ips/_allocate.html | 0 .../nova}/floating_ips/_associate.html | 0 .../nova}/floating_ips/_disassociate.html | 0 .../templates/nova}/floating_ips/_list.html | 6 +- .../nova}/floating_ips/_release.html | 0 .../nova}/floating_ips/associate.html | 6 +- .../templates/nova}/floating_ips/index.html | 10 +- .../nova/templates/nova}/images/_delete.html | 0 .../nova/templates/nova}/images/_form.html | 0 .../nova/templates/nova}/images/_launch.html | 2 +- .../templates/nova}/images/_launch_form.html | 0 .../nova/templates/nova}/images/_list.html | 6 +- .../nova/templates/nova}/images/index.html | 8 +- .../nova/templates/nova}/images/launch.html | 6 +- .../nova/templates/nova}/images/update.html | 6 +- .../nova/templates/nova}/instances/_form.html | 0 .../nova/templates/nova}/instances/_list.html | 16 +- .../templates/nova}/instances/detail.html | 8 +- .../nova/templates/nova}/instances/index.html | 12 +- .../templates/nova}/instances/update.html | 10 +- .../nova/templates/nova}/instances/usage.csv | 0 .../nova/templates/nova}/instances/usage.html | 10 +- .../templates/nova}/keypairs/_delete.html | 0 .../nova/templates/nova}/keypairs/_form.html | 0 .../nova/templates/nova}/keypairs/_list.html | 2 +- .../nova/templates/nova}/keypairs/create.html | 8 +- .../nova/templates/nova}/keypairs/import.html | 8 +- .../nova/templates/nova}/keypairs/index.html | 16 +- .../templates/nova}/networks/_delete.html | 0 .../nova}/networks/_delete_port.html | 0 .../nova}/networks/_detach_port.html | 0 .../templates/nova}/networks/_detail.html | 8 +- .../nova/templates/nova}/networks/_form.html | 0 .../nova/templates/nova}/networks/_list.html | 6 +- .../templates/nova}/networks/_rename.html | 0 .../nova}/networks/_rename_form.html | 0 .../nova}/networks/_toggle_port.html | 0 .../nova/templates/nova}/networks/create.html | 8 +- .../nova/templates/nova/networks/detail.html | 31 + .../nova/templates/nova}/networks/index.html | 12 +- .../nova/templates/nova}/networks/rename.html | 8 +- .../nova/templates/nova}/objects/_copy.html | 0 .../nova/templates/nova}/objects/_delete.html | 0 .../nova/templates/nova}/objects/_filter.html | 0 .../nova/templates/nova}/objects/_form.html | 0 .../nova/templates/nova}/objects/_list.html | 6 +- .../nova/templates/nova}/objects/_paging.html | 0 .../nova/templates/nova}/objects/copy.html | 8 +- .../nova/templates/nova}/objects/index.html | 12 +- .../nova/templates/nova}/objects/upload.html | 8 +- .../nova/templates/nova}/ports/_attach.html | 0 .../nova/templates/nova}/ports/_create.html | 0 .../nova/templates/nova}/ports/attach.html | 8 +- .../nova/templates/nova}/ports/create.html | 8 +- .../nova}/security_groups/_delete.html | 0 .../nova}/security_groups/_delete_rule.html | 0 .../nova}/security_groups/_form.html | 0 .../nova}/security_groups/_list.html | 4 +- .../nova}/security_groups/create.html | 6 +- .../nova}/security_groups/edit_rules.html | 6 +- .../nova}/security_groups/index.html | 12 +- .../nova/templates/nova}/settings.html | 6 +- .../nova/templates/nova}/snapshots/_form.html | 0 .../templates/nova}/snapshots/create.html | 8 +- .../nova/templates/nova}/snapshots/index.html | 10 +- .../templates/nova}/volumes/_attach_form.html | 0 .../nova/templates/nova}/volumes/_delete.html | 0 .../templates/nova}/volumes/_detach_form.html | 0 .../nova/templates/nova}/volumes/_form.html | 0 .../nova/templates/nova}/volumes/_list.html | 10 +- .../nova/templates/nova}/volumes/attach.html | 8 +- .../nova/templates/nova}/volumes/create.html | 8 +- .../nova/templates/nova}/volumes/detail.html | 6 +- .../nova/templates/nova}/volumes/index.html | 10 +- .../dashboards/nova/volumes/__init__.py | 0 .../horizon/dashboards/nova/volumes/forms.py | 92 +- .../horizon/dashboards/nova/volumes/panel.py | 26 + .../horizon/dashboards/nova/volumes/tests.py | 0 .../horizon/dashboards/nova/volumes/urls.py | 25 + .../horizon/dashboards/nova/volumes/views.py | 110 + .../horizon/dashboards/settings/__init__.py | 0 .../horizon/dashboards/settings/dashboard.py | 30 + .../horizon/dashboards/settings/models.py | 18 +- .../settings/templates/settings/base.html | 13 + .../templates/settings/user/settings.html | 32 + .../dashboards/settings/user/__init__.py | 0 .../horizon/dashboards/settings/user/panel.py | 26 + .../horizon/dashboards/settings/user/urls.py | 28 + .../horizon/dashboards/syspanel/__init__.py | 0 .../horizon/dashboards/syspanel/dashboard.py | 32 + .../dashboards/syspanel/flavors/__init__.py | 0 .../dashboards/syspanel/flavors/forms.py | 67 +- .../dashboards/syspanel/flavors/panel.py | 30 + .../dashboards/syspanel/flavors/tests.py | 0 .../dashboards/syspanel/flavors/urls.py | 26 + .../dashboards/syspanel/flavors/views.py | 77 + .../dashboards/syspanel/images/__init__.py | 0 .../dashboards/syspanel/images/forms.py | 83 + .../dashboards/syspanel/images/panel.py | 30 + .../dashboards/syspanel/images/tests.py | 0 .../dashboards/syspanel/images/urls.py | 26 + .../dashboards/syspanel/images/views.py | 111 +- .../dashboards/syspanel/instances/__init__.py | 0 .../dashboards/syspanel/instances/panel.py | 31 + .../dashboards/syspanel/instances/tests.py | 0 .../dashboards/syspanel/instances/urls.py | 36 + .../dashboards/syspanel/instances/views.py | 138 +- horizon/horizon/dashboards/syspanel/models.py | 23 + .../dashboards/syspanel/overview/__init__.py | 0 .../dashboards/syspanel/overview/panel.py | 31 + .../dashboards/syspanel/overview/urls.py | 26 + .../dashboards/syspanel/quotas/__init__.py | 0 .../dashboards/syspanel/quotas/panel.py | 30 + .../dashboards/syspanel/quotas/tests.py | 0 .../dashboards/syspanel/quotas/urls.py | 25 + .../dashboards/syspanel/quotas/views.py | 22 +- .../dashboards/syspanel/services/__init__.py | 0 .../dashboards/syspanel/services/forms.py | 58 + .../dashboards/syspanel/services/panel.py | 30 + .../dashboards/syspanel/services/tests.py | 0 .../dashboards/syspanel/services/urls.py | 25 + .../dashboards/syspanel/services/views.py | 59 +- .../syspanel/templates}/syspanel/base.html | 11 +- .../templates}/syspanel/flavors/_create.html | 2 +- .../templates}/syspanel/flavors/_delete.html | 0 .../templates}/syspanel/flavors/_form.html | 0 .../templates}/syspanel/flavors/_list.html | 2 +- .../templates}/syspanel/flavors/create.html | 6 +- .../templates/syspanel/flavors/index.html | 19 + .../templates}/syspanel/images/_delete.html | 0 .../templates}/syspanel/images/_form.html | 0 .../templates}/syspanel/images/_list.html | 6 +- .../templates}/syspanel/images/_toggle.html | 0 .../templates}/syspanel/images/index.html | 8 +- .../templates}/syspanel/images/update.html | 6 +- .../templates}/syspanel/instances/_list.html | 12 +- .../templates}/syspanel/instances/detail.html | 10 +- .../templates}/syspanel/instances/index.html | 12 +- .../syspanel/instances/tenant_usage.csv | 0 .../syspanel/instances/tenant_usage.html | 4 +- .../templates}/syspanel/instances/usage.csv | 0 .../templates}/syspanel/instances/usage.html | 6 +- .../templates}/syspanel/quotas/index.html | 6 +- .../templates}/syspanel/services/_list.html | 2 +- .../templates}/syspanel/services/_toggle.html | 0 .../templates}/syspanel/services/index.html | 8 +- .../syspanel/tenants/_add_user.html | 0 .../syspanel/tenants/_create_form.html | 2 +- .../templates}/syspanel/tenants/_delete.html | 0 .../templates}/syspanel/tenants/_form.html | 0 .../templates}/syspanel/tenants/_list.html | 8 +- .../syspanel/tenants/_quotas_form.html | 0 .../syspanel/tenants/_remove_user.html | 0 .../syspanel/tenants/_update_form.html | 2 +- .../syspanel/tenants/_update_quotas_form.html | 2 +- .../templates}/syspanel/tenants/create.html | 6 +- .../templates}/syspanel/tenants/index.html | 10 +- .../templates}/syspanel/tenants/quotas.html | 8 +- .../templates}/syspanel/tenants/update.html | 6 +- .../templates}/syspanel/tenants/users.html | 6 +- .../syspanel/users/_create_form.html | 2 +- .../templates}/syspanel/users/_delete.html | 0 .../syspanel/users/_enable_disable.html | 0 .../templates}/syspanel/users/_form.html | 0 .../syspanel/users/_toggle_enabled.html | 0 .../syspanel/users/_update_form.html | 2 +- .../templates}/syspanel/users/create.html | 6 +- .../templates}/syspanel/users/index.html | 14 +- .../templates}/syspanel/users/update.html | 6 +- .../dashboards/syspanel/tenants/__init__.py | 0 .../dashboards/syspanel/tenants/forms.py | 155 +- .../dashboards/syspanel/tenants/panel.py | 30 + .../dashboards/syspanel/tenants/tests.py | 0 .../dashboards/syspanel/tenants/urls.py | 29 + .../dashboards/syspanel/tenants/views.py | 143 ++ .../dashboards/syspanel/users/__init__.py | 0 .../dashboards/syspanel/users/forms.py | 102 + .../dashboards/syspanel/users/panel.py | 30 + .../dashboards/syspanel/users/tests.py | 28 +- .../horizon/dashboards/syspanel/users/urls.py | 26 + .../dashboards/syspanel/users/views.py | 150 +- horizon/horizon/decorators.py | 86 + horizon/horizon/exceptions.py | 40 + .../horizon}/forms.py | 41 +- .../horizon}/locale/es/LC_MESSAGES/django.mo | Bin 425 -> 425 bytes .../horizon/locale/es/LC_MESSAGES/django.po | 1971 +++++++++++++++++ .../horizon}/locale/fr/LC_MESSAGES/django.mo | Bin 420 -> 420 bytes .../horizon/locale/fr/LC_MESSAGES/django.po | 1971 +++++++++++++++++ .../horizon/locale/ja/LC_MESSAGES/django.mo | Bin 0 -> 2528 bytes .../horizon}/locale/ja/LC_MESSAGES/django.po | 1856 ++++++++-------- .../horizon}/locale/pl/LC_MESSAGES/django.mo | Bin 936 -> 936 bytes .../horizon}/locale/pl/LC_MESSAGES/django.po | 1826 +++++++-------- .../horizon/locale/pt}/LC_MESSAGES/django.mo | Bin 382 -> 382 bytes .../horizon/locale/pt/LC_MESSAGES/django.po | 1970 ++++++++++++++++ .../locale/zh-cn}/LC_MESSAGES/django.mo | Bin 382 -> 382 bytes .../locale/zh-cn/LC_MESSAGES/django.po | 1970 ++++++++++++++++ .../locale/zh-tw}/LC_MESSAGES/django.mo | Bin 382 -> 382 bytes .../locale/zh-tw/LC_MESSAGES/django.po | 1970 ++++++++++++++++ .../horizon/middleware.py | 57 +- horizon/horizon/models.py | 23 + .../urls.py => horizon/horizon/site_urls.py | 21 +- .../horizon/templates/horizon/_nav_list.html | 10 + .../templates/horizon/_subnav_list.html | 14 + .../templates/horizon/auth/_login.html | 17 + .../templates/horizon}/auth/_switch.html | 12 +- .../horizon}/common/_page_header.html | 6 +- .../templates/horizon/common/_sidebar.html | 5 + .../horizon}/common/_sidebar_module.html | 4 +- .../horizon/common/instances/_reboot.html | 9 + .../horizon/common/instances/_terminate.html | 9 + horizon/horizon/templatetags/__init__.py | 0 .../horizon}/templatetags/branding.py | 2 +- horizon/horizon/templatetags/horizon.py | 79 + .../horizon}/templatetags/parse_date.py | 0 .../horizon}/templatetags/sizeformat.py | 0 horizon/horizon/templatetags/swift_paging.py | 35 + .../horizon}/templatetags/truncate_filter.py | 0 horizon/horizon/test.py | 212 ++ .../horizon}/tests/__init__.py | 2 +- horizon/horizon/tests/api_tests/__init__.py | 29 + horizon/horizon/tests/api_tests/base.py | 112 + horizon/horizon/tests/api_tests/glance.py | 174 ++ horizon/horizon/tests/api_tests/keystone.py | 366 +++ horizon/horizon/tests/api_tests/nova.py | 697 ++++++ horizon/horizon/tests/api_tests/swift.py | 260 +++ horizon/horizon/tests/api_tests/utils.py | 99 + .../horizon/tests}/auth_tests.py | 45 +- horizon/horizon/tests/base_tests.py | 133 ++ .../horizon/tests/context_processor_tests.py | 45 + .../horizon/tests/templates/base-sidebar.html | 0 horizon/horizon/tests/templates/base.html | 0 horizon/horizon/tests/templates/splash.html | 0 .../tests/templates/switch_tenants.html | 0 .../horizon/tests/templatetag_tests.py | 28 +- .../horizon}/tests/testsettings.py | 62 +- .../horizon}/tests/testurls.py | 15 +- .../horizon}/tests/views.py | 0 horizon/horizon/users.py | 123 + .../horizon}/version.py | 0 horizon/horizon/views/__init__.py | 0 .../views.py => horizon/horizon/views/auth.py | 32 +- horizon/horizon/views/auth_forms.py | 141 ++ {django-openstack => horizon}/setup.py | 11 +- openstack-dashboard/README | 49 +- openstack-dashboard/dashboard/manage.py | 3 + openstack-dashboard/dashboard/middleware.py | 1 + openstack-dashboard/dashboard/settings.py | 20 +- .../static/dashboard/images/favicon.ico | Bin 0 -> 1150 bytes .../dashboard/templates/_login.html | 2 +- .../dashboard/templates/_switch.html | 2 +- .../dashboard/templates/_topbar.html | 22 +- .../dashboard/templates/base.html | 1 + .../dashboard/templates/switch_tenants.html | 4 +- openstack-dashboard/dashboard/urls.py | 15 +- openstack-dashboard/dashboard/views.py | 20 +- .../local/local_settings.py.example | 97 +- openstack-dashboard/tools/install_venv.py | 11 +- openstack-dashboard/tools/pip-requires | 22 +- openstack-dashboard/tools/with_venv.sh | 1 - run_tests.sh | 75 +- 403 files changed, 21536 insertions(+), 19149 deletions(-) delete mode 100644 django-openstack/README delete mode 100644 django-openstack/django_openstack/api.py delete mode 100644 django-openstack/django_openstack/context_processors.py delete mode 100644 django-openstack/django_openstack/dash/urls.py delete mode 100644 django-openstack/django_openstack/dash/views/containers.py delete mode 100644 django-openstack/django_openstack/dash/views/networks.py delete mode 100644 django-openstack/django_openstack/decorators.py delete mode 100644 django-openstack/django_openstack/exceptions.py delete mode 100644 django-openstack/django_openstack/locale/es/LC_MESSAGES/django.po delete mode 100644 django-openstack/django_openstack/locale/fr/LC_MESSAGES/django.po delete mode 100644 django-openstack/django_openstack/locale/ja/LC_MESSAGES/django.mo delete mode 100644 django-openstack/django_openstack/locale/pt/LC_MESSAGES/django.po delete mode 100644 django-openstack/django_openstack/locale/zh-cn/LC_MESSAGES/django.po delete mode 100644 django-openstack/django_openstack/locale/zh-tw/LC_MESSAGES/django.po delete mode 100644 django-openstack/django_openstack/signals.py delete mode 100644 django-openstack/django_openstack/syspanel/urls.py delete mode 100644 django-openstack/django_openstack/templates/django_openstack/auth/_login.html delete mode 100644 django-openstack/django_openstack/templates/django_openstack/common/instances/_reboot.html delete mode 100644 django-openstack/django_openstack/templates/django_openstack/common/instances/_terminate.html delete mode 100644 django-openstack/django_openstack/templates/django_openstack/dash/_sidebar.html delete mode 100644 django-openstack/django_openstack/templates/django_openstack/dash/containers/index.html delete mode 100644 django-openstack/django_openstack/templates/django_openstack/dash/networks/detail.html delete mode 100644 django-openstack/django_openstack/templates/django_openstack/syspanel/_sidebar.html delete mode 100644 django-openstack/django_openstack/templates/django_openstack/syspanel/flavors/index.html delete mode 100644 django-openstack/django_openstack/templatetags/templatetags/sidebar_modules.py delete mode 100644 django-openstack/django_openstack/templatetags/templatetags/swift_paging.py delete mode 100644 django-openstack/django_openstack/test.py delete mode 100644 django-openstack/django_openstack/tests/api_tests.py delete mode 100644 django-openstack/django_openstack/tests/broken/README delete mode 100644 django-openstack/django_openstack/tests/broken/base.py delete mode 100644 django-openstack/django_openstack/tests/broken/credential_tests.py delete mode 100644 django-openstack/django_openstack/tests/broken/image_tests.py delete mode 100644 django-openstack/django_openstack/tests/broken/instance_tests.py delete mode 100644 django-openstack/django_openstack/tests/broken/keypair_tests.py delete mode 100644 django-openstack/django_openstack/tests/broken/region_tests.py delete mode 100644 django-openstack/django_openstack/tests/broken/test_models.py delete mode 100644 django-openstack/django_openstack/tests/broken/volume_tests.py delete mode 100644 django-openstack/django_openstack/tests/context_processor_tests.py delete mode 100644 django-openstack/django_openstack/tests/templatetag_tests.py delete mode 100644 django-openstack/django_openstack/tests/view_tests/base.py delete mode 100644 django-openstack/django_openstack/tests/view_tests/dash/container_tests.py delete mode 100644 django-openstack/django_openstack/tests/view_tests/dash/port_tests.py delete mode 100755 doc/generate_autodoc_index.py delete mode 100644 doc/source/index.rst delete mode 100644 doc/source/testing.rst rename {doc => docs}/Makefile (100%) rename django-openstack/django_openstack/__init__.py => docs/source/_static/.gitignore (100%) rename {doc => docs}/source/conf.py (70%) create mode 100644 docs/source/faq.rst create mode 100644 docs/source/glossary.rst create mode 100644 docs/source/index.rst create mode 100644 docs/source/intro.rst create mode 100644 docs/source/quickstart.rst create mode 100644 docs/source/ref/context_processors.rst create mode 100644 docs/source/ref/decorators.rst create mode 100644 docs/source/ref/exceptions.rst create mode 100644 docs/source/ref/forms.rst create mode 100644 docs/source/ref/horizon.rst create mode 100644 docs/source/ref/middleware.rst create mode 100644 docs/source/ref/run_tests.rst create mode 100644 docs/source/ref/users.rst create mode 100644 docs/source/ref/views.rst create mode 100644 docs/source/testing.rst rename {django-openstack => horizon}/LICENSE (100%) rename {django-openstack => horizon}/Makefile (94%) create mode 100644 horizon/README rename {django-openstack => horizon}/bootstrap.py (100%) rename {django-openstack => horizon}/buildout.cfg (94%) create mode 100644 horizon/horizon/__init__.py create mode 100644 horizon/horizon/api/__init__.py create mode 100644 horizon/horizon/api/base.py create mode 100644 horizon/horizon/api/deprecated.py create mode 100644 horizon/horizon/api/glance.py create mode 100644 horizon/horizon/api/keystone.py create mode 100644 horizon/horizon/api/nova.py create mode 100644 horizon/horizon/api/quantum.py create mode 100644 horizon/horizon/api/swift.py create mode 100644 horizon/horizon/base.py create mode 100644 horizon/horizon/context_processors.py rename {django-openstack/django_openstack/auth => horizon/horizon/dashboards}/__init__.py (100%) rename {django-openstack/django_openstack/dash => horizon/horizon/dashboards/nova}/__init__.py (100%) rename {django-openstack/django_openstack/dash/views => horizon/horizon/dashboards/nova/containers}/__init__.py (100%) rename django-openstack/django_openstack/dash/views/objects.py => horizon/horizon/dashboards/nova/containers/forms.py (59%) create mode 100644 horizon/horizon/dashboards/nova/containers/panel.py rename django-openstack/django_openstack/tests/view_tests/dash/object_tests.py => horizon/horizon/dashboards/nova/containers/tests.py (51%) rename django-openstack/django_openstack/utils.py => horizon/horizon/dashboards/nova/containers/urls.py (57%) create mode 100644 horizon/horizon/dashboards/nova/containers/views.py create mode 100644 horizon/horizon/dashboards/nova/dashboard.py rename {django-openstack/django_openstack/middleware => horizon/horizon/dashboards/nova/floating_ips}/__init__.py (100%) rename django-openstack/django_openstack/dash/views/floating_ips.py => horizon/horizon/dashboards/nova/floating_ips/forms.py (68%) create mode 100644 horizon/horizon/dashboards/nova/floating_ips/panel.py rename django-openstack/django_openstack/tests/view_tests/dash/floating_ip_tests.py => horizon/horizon/dashboards/nova/floating_ips/tests.py (71%) create mode 100644 horizon/horizon/dashboards/nova/floating_ips/urls.py create mode 100644 horizon/horizon/dashboards/nova/floating_ips/views.py rename {django-openstack/django_openstack/syspanel => horizon/horizon/dashboards/nova/images}/__init__.py (100%) rename django-openstack/django_openstack/dash/views/images.py => horizon/horizon/dashboards/nova/images/forms.py (61%) rename django-openstack/django_openstack/syspanel/forms.py => horizon/horizon/dashboards/nova/images/panel.py (83%) rename django-openstack/django_openstack/tests/view_tests/dash/images_tests.py => horizon/horizon/dashboards/nova/images/tests.py (85%) create mode 100644 horizon/horizon/dashboards/nova/images/urls.py create mode 100644 horizon/horizon/dashboards/nova/images/views.py rename {django-openstack/django_openstack/syspanel/views => horizon/horizon/dashboards/nova/instances}/__init__.py (100%) create mode 100644 horizon/horizon/dashboards/nova/instances/forms.py create mode 100644 horizon/horizon/dashboards/nova/instances/panel.py rename django-openstack/django_openstack/tests/view_tests/dash/instance_tests.py => horizon/horizon/dashboards/nova/instances/tests.py (72%) create mode 100644 horizon/horizon/dashboards/nova/instances/urls.py rename django-openstack/django_openstack/dash/views/instances.py => horizon/horizon/dashboards/nova/instances/views.py (56%) rename {django-openstack/django_openstack/templatetags => horizon/horizon/dashboards/nova/keypairs}/__init__.py (100%) rename django-openstack/django_openstack/dash/views/keypairs.py => horizon/horizon/dashboards/nova/keypairs/forms.py (64%) create mode 100644 horizon/horizon/dashboards/nova/keypairs/panel.py rename django-openstack/django_openstack/tests/view_tests/dash/keypair_tests.py => horizon/horizon/dashboards/nova/keypairs/tests.py (72%) create mode 100644 horizon/horizon/dashboards/nova/keypairs/urls.py create mode 100644 horizon/horizon/dashboards/nova/keypairs/views.py rename {django-openstack/django_openstack => horizon/horizon/dashboards/nova}/models.py (100%) rename {django-openstack/django_openstack/templatetags/templatetags => horizon/horizon/dashboards/nova/networks}/__init__.py (100%) rename django-openstack/django_openstack/dash/views/ports.py => horizon/horizon/dashboards/nova/networks/forms.py (68%) create mode 100644 horizon/horizon/dashboards/nova/networks/panel.py rename django-openstack/django_openstack/tests/view_tests/dash/network_tests.py => horizon/horizon/dashboards/nova/networks/tests.py (63%) create mode 100644 horizon/horizon/dashboards/nova/networks/urls.py create mode 100644 horizon/horizon/dashboards/nova/networks/views.py rename {django-openstack/django_openstack/tests/view_tests => horizon/horizon/dashboards/nova/overview}/__init__.py (100%) create mode 100644 horizon/horizon/dashboards/nova/overview/panel.py rename {django-openstack/django_openstack/auth => horizon/horizon/dashboards/nova/overview}/urls.py (75%) rename {django-openstack/django_openstack/tests/view_tests/dash => horizon/horizon/dashboards/nova/security_groups}/__init__.py (100%) rename django-openstack/django_openstack/dash/views/security_groups.py => horizon/horizon/dashboards/nova/security_groups/forms.py (63%) create mode 100644 horizon/horizon/dashboards/nova/security_groups/panel.py rename django-openstack/django_openstack/tests/view_tests/dash/security_groups_tests.py => horizon/horizon/dashboards/nova/security_groups/tests.py (68%) create mode 100644 horizon/horizon/dashboards/nova/security_groups/urls.py create mode 100644 horizon/horizon/dashboards/nova/security_groups/views.py rename {django-openstack/django_openstack/tests/view_tests/syspanel => horizon/horizon/dashboards/nova/snapshots}/__init__.py (100%) create mode 100644 horizon/horizon/dashboards/nova/snapshots/forms.py create mode 100644 horizon/horizon/dashboards/nova/snapshots/panel.py rename django-openstack/django_openstack/tests/view_tests/dash/snapshots_tests.py => horizon/horizon/dashboards/nova/snapshots/tests.py (67%) create mode 100644 horizon/horizon/dashboards/nova/snapshots/urls.py rename django-openstack/django_openstack/dash/views/snapshots.py => horizon/horizon/dashboards/nova/snapshots/views.py (55%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/base.html (50%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/containers/_delete.html (100%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/containers/_form.html (100%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/containers/_list.html (57%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/containers/create.html (80%) create mode 100644 horizon/horizon/dashboards/nova/templates/nova/containers/index.html rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/floating_ips/_allocate.html (100%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/floating_ips/_associate.html (100%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/floating_ips/_disassociate.html (100%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/floating_ips/_list.html (62%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/floating_ips/_release.html (100%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/floating_ips/associate.html (69%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/floating_ips/index.html (55%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/images/_delete.html (100%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/images/_form.html (100%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/images/_launch.html (67%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/images/_launch_form.html (100%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/images/_list.html (70%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/images/index.html (61%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/images/launch.html (87%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/images/update.html (70%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/instances/_form.html (100%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/instances/_list.html (68%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/instances/detail.html (89%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/instances/index.html (77%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/instances/update.html (69%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/instances/usage.csv (100%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/instances/usage.html (88%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/keypairs/_delete.html (100%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/keypairs/_form.html (100%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/keypairs/_list.html (77%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/keypairs/create.html (76%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/keypairs/import.html (69%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/keypairs/index.html (51%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/networks/_delete.html (100%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/networks/_delete_port.html (100%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/networks/_detach_port.html (100%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/networks/_detail.html (70%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/networks/_form.html (100%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/networks/_list.html (65%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/networks/_rename.html (100%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/networks/_rename_form.html (100%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/networks/_toggle_port.html (100%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/networks/create.html (62%) create mode 100644 horizon/horizon/dashboards/nova/templates/nova/networks/detail.html rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/networks/index.html (56%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/networks/rename.html (67%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/objects/_copy.html (100%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/objects/_delete.html (100%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/objects/_filter.html (100%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/objects/_form.html (100%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/objects/_list.html (58%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/objects/_paging.html (100%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/objects/copy.html (63%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/objects/index.html (55%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/objects/upload.html (70%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/ports/_attach.html (100%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/ports/_create.html (100%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/ports/attach.html (76%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/ports/create.html (62%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/security_groups/_delete.html (100%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/security_groups/_delete_rule.html (100%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/security_groups/_form.html (100%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/security_groups/_list.html (65%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/security_groups/create.html (68%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/security_groups/edit_rules.html (87%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/security_groups/index.html (59%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/settings.html (85%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/snapshots/_form.html (100%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/snapshots/create.html (66%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/snapshots/index.html (62%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/volumes/_attach_form.html (100%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/volumes/_delete.html (100%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/volumes/_detach_form.html (100%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/volumes/_form.html (100%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/volumes/_list.html (74%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/volumes/attach.html (56%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/volumes/create.html (65%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/volumes/detail.html (85%) rename {django-openstack/django_openstack/templates/django_openstack/dash => horizon/horizon/dashboards/nova/templates/nova}/volumes/index.html (58%) rename django-openstack/django_openstack/tests/templates/base-sidebar.html => horizon/horizon/dashboards/nova/volumes/__init__.py (100%) rename django-openstack/django_openstack/dash/views/volumes.py => horizon/horizon/dashboards/nova/volumes/forms.py (56%) create mode 100644 horizon/horizon/dashboards/nova/volumes/panel.py create mode 100644 horizon/horizon/dashboards/nova/volumes/tests.py create mode 100644 horizon/horizon/dashboards/nova/volumes/urls.py create mode 100644 horizon/horizon/dashboards/nova/volumes/views.py create mode 100644 horizon/horizon/dashboards/settings/__init__.py create mode 100644 horizon/horizon/dashboards/settings/dashboard.py rename django-openstack/django_openstack/tests/dependency_tests.py => horizon/horizon/dashboards/settings/models.py (60%) create mode 100644 horizon/horizon/dashboards/settings/templates/settings/base.html create mode 100644 horizon/horizon/dashboards/settings/templates/settings/user/settings.html create mode 100644 horizon/horizon/dashboards/settings/user/__init__.py create mode 100644 horizon/horizon/dashboards/settings/user/panel.py create mode 100644 horizon/horizon/dashboards/settings/user/urls.py create mode 100644 horizon/horizon/dashboards/syspanel/__init__.py create mode 100644 horizon/horizon/dashboards/syspanel/dashboard.py create mode 100644 horizon/horizon/dashboards/syspanel/flavors/__init__.py rename django-openstack/django_openstack/syspanel/views/flavors.py => horizon/horizon/dashboards/syspanel/flavors/forms.py (56%) create mode 100644 horizon/horizon/dashboards/syspanel/flavors/panel.py create mode 100644 horizon/horizon/dashboards/syspanel/flavors/tests.py create mode 100644 horizon/horizon/dashboards/syspanel/flavors/urls.py create mode 100644 horizon/horizon/dashboards/syspanel/flavors/views.py create mode 100644 horizon/horizon/dashboards/syspanel/images/__init__.py create mode 100644 horizon/horizon/dashboards/syspanel/images/forms.py create mode 100644 horizon/horizon/dashboards/syspanel/images/panel.py create mode 100644 horizon/horizon/dashboards/syspanel/images/tests.py create mode 100644 horizon/horizon/dashboards/syspanel/images/urls.py rename django-openstack/django_openstack/syspanel/views/images.py => horizon/horizon/dashboards/syspanel/images/views.py (65%) create mode 100644 horizon/horizon/dashboards/syspanel/instances/__init__.py create mode 100644 horizon/horizon/dashboards/syspanel/instances/panel.py create mode 100644 horizon/horizon/dashboards/syspanel/instances/tests.py create mode 100644 horizon/horizon/dashboards/syspanel/instances/urls.py rename django-openstack/django_openstack/syspanel/views/instances.py => horizon/horizon/dashboards/syspanel/instances/views.py (64%) create mode 100644 horizon/horizon/dashboards/syspanel/models.py create mode 100644 horizon/horizon/dashboards/syspanel/overview/__init__.py create mode 100644 horizon/horizon/dashboards/syspanel/overview/panel.py create mode 100644 horizon/horizon/dashboards/syspanel/overview/urls.py create mode 100644 horizon/horizon/dashboards/syspanel/quotas/__init__.py create mode 100644 horizon/horizon/dashboards/syspanel/quotas/panel.py create mode 100644 horizon/horizon/dashboards/syspanel/quotas/tests.py create mode 100644 horizon/horizon/dashboards/syspanel/quotas/urls.py rename django-openstack/django_openstack/syspanel/views/quotas.py => horizon/horizon/dashboards/syspanel/quotas/views.py (66%) create mode 100644 horizon/horizon/dashboards/syspanel/services/__init__.py create mode 100644 horizon/horizon/dashboards/syspanel/services/forms.py create mode 100644 horizon/horizon/dashboards/syspanel/services/panel.py create mode 100644 horizon/horizon/dashboards/syspanel/services/tests.py create mode 100644 horizon/horizon/dashboards/syspanel/services/urls.py rename django-openstack/django_openstack/syspanel/views/services.py => horizon/horizon/dashboards/syspanel/services/views.py (57%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/base.html (50%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/flavors/_create.html (68%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/flavors/_delete.html (100%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/flavors/_form.html (100%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/flavors/_list.html (83%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/flavors/create.html (87%) create mode 100644 horizon/horizon/dashboards/syspanel/templates/syspanel/flavors/index.html rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/images/_delete.html (100%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/images/_form.html (100%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/images/_list.html (82%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/images/_toggle.html (100%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/images/index.html (50%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/images/update.html (70%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/instances/_list.html (67%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/instances/detail.html (86%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/instances/index.html (79%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/instances/tenant_usage.csv (100%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/instances/tenant_usage.html (95%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/instances/usage.csv (100%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/instances/usage.html (94%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/quotas/index.html (70%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/services/_list.html (93%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/services/_toggle.html (100%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/services/index.html (50%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/tenants/_add_user.html (100%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/tenants/_create_form.html (68%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/tenants/_delete.html (100%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/tenants/_form.html (100%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/tenants/_list.html (54%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/tenants/_quotas_form.html (100%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/tenants/_remove_user.html (100%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/tenants/_update_form.html (68%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/tenants/_update_quotas_form.html (66%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/tenants/create.html (69%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/tenants/index.html (50%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/tenants/quotas.html (62%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/tenants/update.html (68%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/tenants/users.html (84%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/users/_create_form.html (68%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/users/_delete.html (100%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/users/_enable_disable.html (100%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/users/_form.html (100%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/users/_toggle_enabled.html (100%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/users/_update_form.html (68%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/users/create.html (73%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/users/index.html (60%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/dashboards/syspanel/templates}/syspanel/users/update.html (73%) create mode 100644 horizon/horizon/dashboards/syspanel/tenants/__init__.py rename django-openstack/django_openstack/syspanel/views/tenants.py => horizon/horizon/dashboards/syspanel/tenants/forms.py (60%) create mode 100644 horizon/horizon/dashboards/syspanel/tenants/panel.py create mode 100644 horizon/horizon/dashboards/syspanel/tenants/tests.py create mode 100644 horizon/horizon/dashboards/syspanel/tenants/urls.py create mode 100644 horizon/horizon/dashboards/syspanel/tenants/views.py create mode 100644 horizon/horizon/dashboards/syspanel/users/__init__.py create mode 100644 horizon/horizon/dashboards/syspanel/users/forms.py create mode 100644 horizon/horizon/dashboards/syspanel/users/panel.py rename django-openstack/django_openstack/tests/view_tests/syspanel/users_tests.py => horizon/horizon/dashboards/syspanel/users/tests.py (80%) create mode 100644 horizon/horizon/dashboards/syspanel/users/urls.py rename django-openstack/django_openstack/syspanel/views/users.py => horizon/horizon/dashboards/syspanel/users/views.py (51%) create mode 100644 horizon/horizon/decorators.py create mode 100644 horizon/horizon/exceptions.py rename {django-openstack/django_openstack => horizon/horizon}/forms.py (83%) rename {django-openstack/django_openstack => horizon/horizon}/locale/es/LC_MESSAGES/django.mo (90%) create mode 100644 horizon/horizon/locale/es/LC_MESSAGES/django.po rename {django-openstack/django_openstack => horizon/horizon}/locale/fr/LC_MESSAGES/django.mo (90%) create mode 100644 horizon/horizon/locale/fr/LC_MESSAGES/django.po create mode 100644 horizon/horizon/locale/ja/LC_MESSAGES/django.mo rename {django-openstack/django_openstack => horizon/horizon}/locale/ja/LC_MESSAGES/django.po (54%) rename {django-openstack/django_openstack => horizon/horizon}/locale/pl/LC_MESSAGES/django.mo (89%) rename {django-openstack/django_openstack => horizon/horizon}/locale/pl/LC_MESSAGES/django.po (52%) rename {django-openstack/django_openstack/locale/zh-tw => horizon/horizon/locale/pt}/LC_MESSAGES/django.mo (89%) create mode 100644 horizon/horizon/locale/pt/LC_MESSAGES/django.po rename {django-openstack/django_openstack/locale/pt => horizon/horizon/locale/zh-cn}/LC_MESSAGES/django.mo (89%) create mode 100644 horizon/horizon/locale/zh-cn/LC_MESSAGES/django.po rename {django-openstack/django_openstack/locale/zh-cn => horizon/horizon/locale/zh-tw}/LC_MESSAGES/django.mo (89%) create mode 100644 horizon/horizon/locale/zh-tw/LC_MESSAGES/django.po rename django-openstack/django_openstack/middleware/keystone.py => horizon/horizon/middleware.py (55%) create mode 100644 horizon/horizon/models.py rename django-openstack/django_openstack/urls.py => horizon/horizon/site_urls.py (61%) create mode 100644 horizon/horizon/templates/horizon/_nav_list.html create mode 100644 horizon/horizon/templates/horizon/_subnav_list.html create mode 100644 horizon/horizon/templates/horizon/auth/_login.html rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/templates/horizon}/auth/_switch.html (60%) rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/templates/horizon}/common/_page_header.html (70%) create mode 100644 horizon/horizon/templates/horizon/common/_sidebar.html rename {django-openstack/django_openstack/templates/django_openstack => horizon/horizon/templates/horizon}/common/_sidebar_module.html (66%) create mode 100644 horizon/horizon/templates/horizon/common/instances/_reboot.html create mode 100644 horizon/horizon/templates/horizon/common/instances/_terminate.html create mode 100644 horizon/horizon/templatetags/__init__.py rename {django-openstack/django_openstack/templatetags => horizon/horizon}/templatetags/branding.py (97%) create mode 100644 horizon/horizon/templatetags/horizon.py rename {django-openstack/django_openstack/templatetags => horizon/horizon}/templatetags/parse_date.py (100%) rename {django-openstack/django_openstack/templatetags => horizon/horizon}/templatetags/sizeformat.py (100%) create mode 100644 horizon/horizon/templatetags/swift_paging.py rename {django-openstack/django_openstack/templatetags => horizon/horizon}/templatetags/truncate_filter.py (100%) create mode 100644 horizon/horizon/test.py rename {django-openstack/django_openstack => horizon/horizon}/tests/__init__.py (95%) create mode 100644 horizon/horizon/tests/api_tests/__init__.py create mode 100644 horizon/horizon/tests/api_tests/base.py create mode 100644 horizon/horizon/tests/api_tests/glance.py create mode 100644 horizon/horizon/tests/api_tests/keystone.py create mode 100644 horizon/horizon/tests/api_tests/nova.py create mode 100644 horizon/horizon/tests/api_tests/swift.py create mode 100644 horizon/horizon/tests/api_tests/utils.py rename {django-openstack/django_openstack/tests/view_tests => horizon/horizon/tests}/auth_tests.py (84%) create mode 100644 horizon/horizon/tests/base_tests.py create mode 100644 horizon/horizon/tests/context_processor_tests.py create mode 100644 horizon/horizon/tests/templates/base-sidebar.html create mode 100644 horizon/horizon/tests/templates/base.html create mode 100644 horizon/horizon/tests/templates/splash.html create mode 100644 horizon/horizon/tests/templates/switch_tenants.html rename openstack-dashboard/dashboard/tests.py => horizon/horizon/tests/templatetag_tests.py (60%) rename {django-openstack/django_openstack => horizon/horizon}/tests/testsettings.py (59%) rename {django-openstack/django_openstack => horizon/horizon}/tests/testurls.py (63%) rename {django-openstack/django_openstack => horizon/horizon}/tests/views.py (100%) create mode 100644 horizon/horizon/users.py rename {django-openstack/django_openstack => horizon/horizon}/version.py (100%) create mode 100644 horizon/horizon/views/__init__.py rename django-openstack/django_openstack/auth/views.py => horizon/horizon/views/auth.py (89%) create mode 100644 horizon/horizon/views/auth_forms.py rename {django-openstack => horizon}/setup.py (87%) mode change 100755 => 100644 create mode 100644 openstack-dashboard/dashboard/static/dashboard/images/favicon.ico diff --git a/.bzrignore b/.bzrignore index cdd7717225..cda7dea602 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 e6bdfce9de..b797b11f9c 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 edbfb156f5..2492bc597d 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 0323e22091..0000000000 --- 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 60b9f16e3b..0000000000 --- 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 1d1b0a5bca..0000000000 --- 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 82c3a5f2ba..0000000000 --- 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[^/]+)/security_groups/' \ - '(?P[^/]+)/%s$' -INSTANCES = r'^(?P[^/]+)/instances/(?P[^/]+)/%s$' -IMAGES = r'^(?P[^/]+)/images/(?P[^/]+)/%s$' -KEYPAIRS = r'^(?P[^/]+)/keypairs/%s$' -SNAPSHOTS = r'^(?P[^/]+)/snapshots/(?P[^/]+)/%s$' -VOLUMES = r'^(?P[^/]+)/volumes/(?P[^/]+)/%s$' -CONTAINERS = r'^(?P[^/]+)/containers/%s$' -FLOATING_IPS = r'^(?P[^/]+)/floating_ips/(?P[^/]+)/%s$' -OBJECTS = r'^(?P[^/]+)/containers/(?P[^/]+)/%s$' -NETWORKS = r'^(?P[^/]+)/networks/%s$' -PORTS = r'^(?P[^/]+)/networks/(?P[^/]+)/ports/%s$' - -urlpatterns = patterns('django_openstack.dash.views.instances', - url(r'^(?P[^/]+)/$', 'usage', name='dash_usage'), - url(r'^(?P[^/]+)/instances/$', 'index', name='dash_instances'), - url(r'^(?P[^/]+)/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[^/]+)/security_groups/$', 'index', - name='dash_security_groups'), - url(r'^(?P[^/]+)/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[^/]+)/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[^/]+)/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[^/]+)/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[^/]+)/snapshots/$', 'index', name='dash_snapshots'), - url(SNAPSHOTS % 'create', 'create', name='dash_snapshots_create'), -) - -urlpatterns += patterns('django_openstack.dash.views.volumes', - url(r'^(?P[^/]+)/volumes/$', 'index', name='dash_volumes'), - url(r'^(?P[^/]+)/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[^/]+)/copy', - 'copy', name='dash_object_copy'), - url(OBJECTS % '(?P[^/]+)/download', - 'download', name='dash_objects_download'), -) - -urlpatterns += patterns('django_openstack.dash.views.networks', - url(r'^(?P[^/]+)/networks/$', 'index', name='dash_networks'), - url(NETWORKS % 'create', 'create', name='dash_network_create'), - url(NETWORKS % '(?P[^/]+)/detail', 'detail', - name='dash_networks_detail'), - url(NETWORKS % '(?P[^/]+)/rename', 'rename', - name='dash_network_rename'), -) - -urlpatterns += patterns('django_openstack.dash.views.ports', - url(PORTS % 'create', 'create', name='dash_ports_create'), - url(PORTS % '(?P[^/]+)/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 fada57e55c..0000000000 --- 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 95682197e1..0000000000 --- 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 a56e819c0b..0000000000 --- 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 09856350b5..0000000000 --- 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 2e3e96351d..0000000000 --- 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 \n" -"Language-Team: LANGUAGE \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 Images Page." -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.

You can launch an instance from " -"the Images Page." -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 Object Upload " -"Page >>" -msgstr "" - -#: templates/django_openstack/dash/objects/index.html:34 -msgid "Upload New Object >>" -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 "" -"

Select an interface from the list on the left to attach it to this port.\n" -"

Only interfaces that are not connected to any existing port are " -"shown

\n" -"

If you want to reconnect a connected interface, please detach it " -"first

" -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. Create A " -"Security Group >>" -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. View Running Instances >>" -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 Images Page." -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 da68a58fe0..0000000000 --- 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 \n" -"Language-Team: LANGUAGE \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 Images Page." -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.

You can launch an instance from " -"the Images Page." -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 Object Upload " -"Page >>" -msgstr "" - -#: templates/django_openstack/dash/objects/index.html:34 -msgid "Upload New Object >>" -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 "" -"

Select an interface from the list on the left to attach it to this port.\n" -"

Only interfaces that are not connected to any existing port are " -"shown

\n" -"

If you want to reconnect a connected interface, please detach it " -"first

" -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. Create A " -"Security Group >>" -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. View Running Instances >>" -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 Images Page." -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 0a426594fa6c607a51d8ac69667efcac0cd3c89b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2564 zcmZ{kYiv|S6vqd_*Wv@g2cpPDsZz-;TQm{3yeciV(wAjRg5k?_cW5u&y?1lxZjnR{ zyH}dFP=h7qSrL&(t&~D|ONE&D4Nd%LB=O78?Gj^1jL}aT|L1nfHUV$;%x})jnRCvZ zbMO8-b6Ow6vk3A$#GArc8Ti9}81P)0%GiV8W$-cZJFWi&&V>Fm_yG7DI34^0d<6U# zoCZ$EK<8(GWH%e6^?4W!Z~;j6mEgl*Blr-w5qumJT2F)cv5&OwYwpzS1Ihm(&0`?N zJ*o9`Ao;tZc^#xUH#Bd86#sYde(-OQ{QaXj4U6P&I!Jc2z+!MNNcmTRvftHK8Bv3pBddix2}swMQv~Z;-w-Rvz;#$Chlh zE4U|&wPI_ETdr2)tb)tdW{10RW1a9k%WjdZLL`JI02yzzazE?9%> zY)0m0b=+K!bu=boI4MELV{K-9qLZOUk#bzmtd%WR+YxDg}D+k|Yjkb4{7Y$ds|%(H{(s-zWn+R`pB*_>K|bK{jaqk<vx}aom=IO~iPIr?@So2-Q~CRu(Q^S`rSec5F}B$YE;=m+{2= z-r`h(TXvZdYvryK-twmC8gpsEj&j{3T(i=SIdQz~5o2ky<%Jp&NG)Nmaoi;OWv2pF zE-x)J#;41}Wg(`rM^tuLWiKlKg!0cqA5#8^@(%fSNQpoI%zyd~8j>{}}w14c}5xBS# zB#z2sr$c4GRN2$Y|C+2&!Ti9s{NN#Yyp_3>>pleY^TEz;auI~kDWV%BdABLBWfQ3ZjlE++p?~x57gg 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 21c8f5b250..0000000000 --- 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 \n" -"Language-Team: LANGUAGE \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 Images Page." -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.

You can launch an instance from " -"the Images Page." -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 Object Upload " -"Page >>" -msgstr "" - -#: templates/django_openstack/dash/objects/index.html:34 -msgid "Upload New Object >>" -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 "" -"

Select an interface from the list on the left to attach it to this port.\n" -"

Only interfaces that are not connected to any existing port are " -"shown

\n" -"

If you want to reconnect a connected interface, please detach it " -"first

" -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. Create A " -"Security Group >>" -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. View Running Instances >>" -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 Images Page." -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 21c8f5b250..0000000000 --- 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 \n" -"Language-Team: LANGUAGE \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 Images Page." -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.

You can launch an instance from " -"the Images Page." -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 Object Upload " -"Page >>" -msgstr "" - -#: templates/django_openstack/dash/objects/index.html:34 -msgid "Upload New Object >>" -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 "" -"

Select an interface from the list on the left to attach it to this port.\n" -"

Only interfaces that are not connected to any existing port are " -"shown

\n" -"

If you want to reconnect a connected interface, please detach it " -"first

" -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. Create A " -"Security Group >>" -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. View Running Instances >>" -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 Images Page." -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 21c8f5b250..0000000000 --- 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 \n" -"Language-Team: LANGUAGE \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 Images Page." -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.

You can launch an instance from " -"the Images Page." -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 Object Upload " -"Page >>" -msgstr "" - -#: templates/django_openstack/dash/objects/index.html:34 -msgid "Upload New Object >>" -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 "" -"

Select an interface from the list on the left to attach it to this port.\n" -"

Only interfaces that are not connected to any existing port are " -"shown

\n" -"

If you want to reconnect a connected interface, please detach it " -"first

" -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. Create A " -"Security Group >>" -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. View Running Instances >>" -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 Images Page." -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 ada0e9299e..0000000000 --- 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: (, - {'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 48dba7a766..0000000000 --- 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[^/]+)/%s$' -IMAGES = r'^images/(?P[^/]+)/%s$' -USERS = r'^users/(?P[^/]+)/%s$' -TENANTS = r'^tenants/(?P[^/]+)/%s$' - - -urlpatterns = patterns('django_openstack.syspanel.views.instances', - url(r'^usage/(?P[^/]+)$', '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 af8d4d20f2..0000000000 --- a/django-openstack/django_openstack/templates/django_openstack/auth/_login.html +++ /dev/null @@ -1,17 +0,0 @@ -{%load i18n%} -
- {% csrf_token %} -
- {% for hidden in form.hidden_fields %} - {{hidden}} - {% endfor %} - {% for field in form.visible_fields %} - {{field.label_tag}} - {{field.errors}} - {{field}} - {% endfor %} - {% block submit %} - - {% endblock %} -
-
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 3758e1d81d..0000000000 --- a/django-openstack/django_openstack/templates/django_openstack/common/instances/_reboot.html +++ /dev/null @@ -1,9 +0,0 @@ -{%load i18n%} -
- {% csrf_token %} - {% for hidden in form.hidden_fields %} - {{hidden}} - {% endfor %} - - -
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 aea97246d5..0000000000 --- a/django-openstack/django_openstack/templates/django_openstack/common/instances/_terminate.html +++ /dev/null @@ -1,9 +0,0 @@ -{%load i18n%} -
- {% csrf_token %} - {% for hidden in form.hidden_fields %} - {{hidden}} - {% endfor %} - - -
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 3a398a3f34..0000000000 --- a/django-openstack/django_openstack/templates/django_openstack/dash/_sidebar.html +++ /dev/null @@ -1,28 +0,0 @@ -{% load sidebar_modules %} -{%load i18n%} - - 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 6230c26fef..0000000000 --- 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' %} - {% trans "Create New Container"%} >> -{% 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 2898d822e2..0000000000 --- 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 %} - Networks »  - {{network.name}} -{% endblock %} - -{% block dash_main %} - {% if network.ports %} - {% include 'django_openstack/dash/networks/_detail.html' %} - {% trans "Create Ports"%} - {% else %} -
-

{% trans "Info"%}

-

{% trans "There are currently no ports in this network."%} {% trans "Create Ports"%} >>

-
- {% 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 4068f8c3e5..0000000000 --- a/django-openstack/django_openstack/templates/django_openstack/syspanel/_sidebar.html +++ /dev/null @@ -1,18 +0,0 @@ -{% load sidebar_modules %} -{%load i18n%} - - 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 f592f654b1..0000000000 --- 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" %} - {% trans "Create New Flavor"%} -{% 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 c4172e22cc..0000000000 --- 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 774f604058..0000000000 --- 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 3cc4b716ff..0000000000 --- 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 f50d214a59..0000000000 --- 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 a2eec65286..0000000000 --- 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 9947931fd3..0000000000 --- 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 23ac977763..0000000000 --- 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 a2b6769d75..0000000000 --- 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 7f407d4252..0000000000 --- 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 130e2feb18..0000000000 --- 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 bf49cc573e..0000000000 --- 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 8fed250155..0000000000 --- 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 b4ca10e34c..0000000000 --- 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 335845861f..0000000000 --- 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 7ca198e2bc..0000000000 --- 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(, { - '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)), - '

Nixon

') - - # 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)), - '

Nixon

') - - 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 8ec5f419b5..0000000000 --- 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('

' - 'This is a fake httpresponse for testing purposes only' - '

') - - # 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 f9b03ea742..0000000000 --- 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 5d5d827d5e..0000000000 --- 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/doc/generate_autodoc_index.py b/doc/generate_autodoc_index.py deleted file mode 100755 index 8abbeaf85f..0000000000 --- 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 cb6e32787a..0000000000 --- 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 -`_, 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 bab32a8247..0000000000 --- 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 similarity index 100% rename from doc/Makefile rename to docs/Makefile diff --git a/django-openstack/django_openstack/__init__.py b/docs/source/_static/.gitignore similarity index 100% rename from django-openstack/django_openstack/__init__.py rename to docs/source/_static/.gitignore diff --git a/doc/source/conf.py b/docs/source/conf.py similarity index 70% rename from doc/source/conf.py rename to docs/source/conf.py index 164c6560c8..a1f7a3a83b 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 0000000000..26836ef665 --- /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 0000000000..cca874009f --- /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 0000000000..c326d6decc --- /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 +`_, 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 `. + +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 0000000000..83f7819fda --- /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 ` + A short guide to getting started with using Horizon. + + :doc:`Frequently Asked Questions ` + Common questions and answers. + + :doc:`Glossary ` + Common terms and their definitions. diff --git a/docs/source/quickstart.rst b/docs/source/quickstart.rst new file mode 100644 index 0000000000..2e010be955 --- /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 %} + + + +And in your ``sidebar.html`` you might have:: + + {% load horizon %} + + + +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 0000000000..b34c010906 --- /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 0000000000..777afbe5d3 --- /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 0000000000..4151f18f71 --- /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 0000000000..9b30cb8e67 --- /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 0000000000..9206e950e3 --- /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 0000000000..fcca5ff070 --- /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 0000000000..201198ed0d --- /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 0000000000..857358d196 --- /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 0000000000..970609caed --- /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 0000000000..a968ae50d5 --- /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 similarity index 100% rename from django-openstack/LICENSE rename to horizon/LICENSE diff --git a/django-openstack/Makefile b/horizon/Makefile similarity index 94% rename from django-openstack/Makefile rename to horizon/Makefile index 8496df210e..d64cd72bcb 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 0000000000..1b6d6fd33f --- /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 similarity index 100% rename from django-openstack/bootstrap.py rename to horizon/bootstrap.py diff --git a/django-openstack/buildout.cfg b/horizon/buildout.cfg similarity index 94% rename from django-openstack/buildout.cfg rename to horizon/buildout.cfg index 0858569fd3..3910799fde 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 0000000000..c9838c2ff7 --- /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 0000000000..4d0229ad72 --- /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 0000000000..093a214a4a --- /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 0000000000..58f72ead75 --- /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 0000000000..24ac7fbd88 --- /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 0000000000..cdc455169c --- /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 0000000000..1802d1a48d --- /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 0000000000..3d2675c35d --- /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 0000000000..55cfebb527 --- /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 0000000000..10ebfd782b --- /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 "" % 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 "" % 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"" % 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 0000000000..9f0a98780a --- /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 similarity index 100% rename from django-openstack/django_openstack/auth/__init__.py rename to horizon/horizon/dashboards/__init__.py diff --git a/django-openstack/django_openstack/dash/__init__.py b/horizon/horizon/dashboards/nova/__init__.py similarity index 100% rename from django-openstack/django_openstack/dash/__init__.py rename to 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 similarity index 100% rename from django-openstack/django_openstack/dash/views/__init__.py rename to 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 similarity index 59% rename from django-openstack/django_openstack/dash/views/objects.py rename to horizon/horizon/dashboards/nova/containers/forms.py index f8d34e55ee..576f23569d 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 django_openstack import api -from django_openstack import forms +from horizon import api +from horizon import forms -LOG = logging.getLogger('django_openstack.dash') +LOG = logging.getLogger(__name__) + + +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 0000000000..06c95289fd --- /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 similarity index 51% rename from django-openstack/django_openstack/tests/view_tests/dash/object_tests.py rename to horizon/horizon/dashboards/nova/containers/tests.py index 0314394e09..3be112973e 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/django-openstack/django_openstack/utils.py b/horizon/horizon/dashboards/nova/containers/urls.py similarity index 57% rename from django-openstack/django_openstack/utils.py rename to horizon/horizon/dashboards/nova/containers/urls.py index 573e7be4fc..5ad9a367b0 100644 --- a/django-openstack/django_openstack/utils.py +++ b/horizon/horizon/dashboards/nova/containers/urls.py @@ -18,31 +18,19 @@ # License for the specific language governing permissions and limitations # under the License. -import datetime +from django.conf.urls.defaults import patterns, url -def time(): - '''Overrideable version of datetime.datetime.today''' - if time.override_time: - return time.override_time - return datetime.time() - -time.override_time = None +OBJECTS = r'^(?P[^/]+)/%s$' -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 +# 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[^/]+)/copy', + 'object_copy', name='object_copy'), + url(OBJECTS % '(?P[^/]+)/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 0000000000..2f89709e72 --- /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 0000000000..380b2710b7 --- /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 similarity index 100% rename from django-openstack/django_openstack/middleware/__init__.py rename to 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 similarity index 68% rename from django-openstack/django_openstack/dash/views/floating_ips.py rename to horizon/horizon/dashboards/nova/floating_ips/forms.py index 6678f8a803..f7100e3b7d 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 0000000000..cba90145c8 --- /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 similarity index 71% rename from django-openstack/django_openstack/tests/view_tests/dash/floating_ip_tests.py rename to horizon/horizon/dashboards/nova/floating_ips/tests.py index 6a7c05f0ba..3d6925a1d7 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 0000000000..64abd2d1d3 --- /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[^/]+)/associate/$', 'associate', name='associate'), + url(r'^(?P[^/]+)/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 0000000000..8e795decd5 --- /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 similarity index 100% rename from django-openstack/django_openstack/syspanel/__init__.py rename to 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 similarity index 61% rename from django-openstack/django_openstack/dash/views/images.py rename to horizon/horizon/dashboards/nova/images/forms.py index 3ff1d61bd1..806d06210b 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 similarity index 83% rename from django-openstack/django_openstack/syspanel/forms.py rename to horizon/horizon/dashboards/nova/images/panel.py index e8af46ce12..12f293c556 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 similarity index 85% rename from django-openstack/django_openstack/tests/view_tests/dash/images_tests.py rename to horizon/horizon/dashboards/nova/images/tests.py index 075e0e87e2..24e2f5bcba 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 0000000000..3306293d11 --- /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[^/]+)/launch/$', 'launch', name='launch'), + url(r'^(?P[^/]+)/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 0000000000..12e3ef3b6b --- /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 similarity index 100% rename from django-openstack/django_openstack/syspanel/views/__init__.py rename to 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 0000000000..1296008e89 --- /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 0000000000..b4d3b0b8a5 --- /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 similarity index 72% rename from django-openstack/django_openstack/tests/view_tests/dash/instance_tests.py rename to horizon/horizon/dashboards/nova/instances/tests.py index ed5812f71c..e9ec1cec47 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 0000000000..82809f245c --- /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[^/]+)/%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 similarity index 56% rename from django-openstack/django_openstack/dash/views/instances.py rename to horizon/horizon/dashboards/nova/instances/views.py index 6a7261291d..75b975e2ef 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') +from horizon import api +from horizon import forms +from horizon import test +from horizon.dashboards.nova.instances.forms import (TerminateInstance, + RebootInstance, UpdateInstance) -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('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.redirect('horizon:nova:instances:index') - 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.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 similarity index 100% rename from django-openstack/django_openstack/templatetags/__init__.py rename to 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 similarity index 64% rename from django-openstack/django_openstack/dash/views/keypairs.py rename to horizon/horizon/dashboards/nova/keypairs/forms.py index ef077f4b64..fddc1161b3 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 0000000000..8188773855 --- /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 similarity index 72% rename from django-openstack/django_openstack/tests/view_tests/dash/keypair_tests.py rename to horizon/horizon/dashboards/nova/keypairs/tests.py index 45c090c9f8..6f50f52d50 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 0000000000..8080debe05 --- /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 0000000000..b65b64a158 --- /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 similarity index 100% rename from django-openstack/django_openstack/models.py rename to 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 similarity index 100% rename from django-openstack/django_openstack/templatetags/templatetags/__init__.py rename to 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 similarity index 68% rename from django-openstack/django_openstack/dash/views/ports.py rename to horizon/horizon/dashboards/nova/networks/forms.py index ad690cfe86..2a23a094ae 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 0000000000..825c720def --- /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 similarity index 63% rename from django-openstack/django_openstack/tests/view_tests/dash/network_tests.py rename to horizon/horizon/dashboards/nova/networks/tests.py index ebd17046b1..aab9ba8e9a 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/horizon/horizon/dashboards/nova/networks/urls.py b/horizon/horizon/dashboards/nova/networks/urls.py new file mode 100644 index 0000000000..fd0c5ae06b --- /dev/null +++ b/horizon/horizon/dashboards/nova/networks/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 + +urlpatterns = patterns('horizon.dashboards.nova.networks.views', + url(r'^$', 'index', name='index'), + url(r'^create/$', 'create', name='create'), + url(r'^(?P[^/]+)/detail/$', 'detail', name='detail'), + url(r'^(?P[^/]+)/rename/$', 'rename', name='rename'), + url(r'^(?P[^/]+)/ports/create/$', 'port_create', + name='port_create'), + url(r'^(?P[^/]+)/ports/(?P[^/]+)/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 0000000000..69969f6575 --- /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 similarity index 100% rename from django-openstack/django_openstack/tests/view_tests/__init__.py rename to 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 0000000000..fbd5b5d7e7 --- /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 similarity index 75% rename from django-openstack/django_openstack/auth/urls.py rename to horizon/horizon/dashboards/nova/overview/urls.py index ba9b04dc4a..97e1d3da7d 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 - -urlpatterns = patterns('django_openstack.auth.views', - url(r'login/$', 'login', name='auth_login'), - url(r'logout/$', 'logout', name='auth_logout'), - url(r'switch/(?P[^/]+)/$', '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 similarity index 100% rename from django-openstack/django_openstack/tests/view_tests/dash/__init__.py rename to 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 similarity index 63% rename from django-openstack/django_openstack/dash/views/security_groups.py rename to horizon/horizon/dashboards/nova/security_groups/forms.py index 8b88331ddd..1c27f0cbf2 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.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.contrib import messages +from django.core import validators 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 0000000000..344238de26 --- /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 similarity index 68% rename from django-openstack/django_openstack/tests/view_tests/dash/security_groups_tests.py rename to horizon/horizon/dashboards/nova/security_groups/tests.py index 7d7bdee218..de061f6f19 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 0000000000..691a746191 --- /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[^/]+)/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 0000000000..9d6530c40c --- /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 similarity index 100% rename from django-openstack/django_openstack/tests/view_tests/syspanel/__init__.py rename to 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 0000000000..3666c3996a --- /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 0000000000..5b17b1930b --- /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 similarity index 67% rename from django-openstack/django_openstack/tests/view_tests/dash/snapshots_tests.py rename to horizon/horizon/dashboards/nova/snapshots/tests.py index 7317ef7355..c0c70f1831 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 0000000000..64b43af843 --- /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[^/]+)/create', 'create', name='create')) diff --git a/django-openstack/django_openstack/dash/views/snapshots.py b/horizon/horizon/dashboards/nova/snapshots/views.py similarity index 55% rename from django-openstack/django_openstack/dash/views/snapshots.py rename to horizon/horizon/dashboards/nova/snapshots/views.py index 47b5a7b08b..5d99484b76 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 similarity index 50% rename from django-openstack/django_openstack/templates/django_openstack/dash/base.html rename to horizon/horizon/dashboards/nova/templates/nova/base.html index 430a4d995c..2fe83bb648 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 %}
{% 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 similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/dash/containers/_delete.html rename to 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 similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/dash/containers/_form.html rename to 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 similarity index 57% rename from django-openstack/django_openstack/templates/django_openstack/dash/containers/_list.html rename to horizon/horizon/dashboards/nova/templates/nova/containers/_list.html index f15496eabb..fe7828f580 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 @@ {{ container.name }} diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/containers/create.html b/horizon/horizon/dashboards/nova/templates/nova/containers/create.html similarity index 80% rename from django-openstack/django_openstack/templates/django_openstack/dash/containers/create.html rename to horizon/horizon/dashboards/nova/templates/nova/containers/create.html index f0405480c2..4d4cde4e0e 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 %}
- {% include 'django_openstack/dash/containers/_form.html' with form=create_form %} + {% include 'nova/containers/_form.html' with form=create_form %}
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 0000000000..156f4817b8 --- /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' %} + {% trans "Create New Container"%} >> +{% 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 similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/dash/floating_ips/_allocate.html rename to 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 similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/dash/floating_ips/_associate.html rename to 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 similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/dash/floating_ips/_disassociate.html rename to 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 similarity index 62% rename from django-openstack/django_openstack/templates/django_openstack/dash/floating_ips/_list.html rename to horizon/horizon/dashboards/nova/templates/nova/floating_ips/_list.html index 156d625e5b..92d1188494 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 @@
    -
  • {% include "django_openstack/dash/floating_ips/_release.html" with form=release_form %}
  • +
  • {% include "nova/floating_ips/_release.html" with form=release_form %}
  • {% if ip.fixed_ip %} -
  • {% include "django_openstack/dash/floating_ips/_disassociate.html" with form=disassociate_form %}
  • +
  • {% include "nova/floating_ips/_disassociate.html" with form=disassociate_form %}
  • {% else %} -
  • {%trans "Associate to instance"%}
  • +
  • {%trans "Associate to instance"%}
  • {% endif %}
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 similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/dash/floating_ips/_release.html rename to 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 similarity index 69% rename from django-openstack/django_openstack/templates/django_openstack/dash/floating_ips/associate.html rename to horizon/horizon/dashboards/nova/templates/nova/floating_ips/associate.html index ff05fa27c8..5d73f73eb8 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 %}
- {% include 'django_openstack/dash/floating_ips/_associate.html' with form=associate_form %} + {% include 'nova/floating_ips/_associate.html' with form=associate_form %}
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 similarity index 55% rename from django-openstack/django_openstack/templates/django_openstack/dash/floating_ips/index.html rename to horizon/horizon/dashboards/nova/templates/nova/floating_ips/index.html index fa224670ae..013718a0a3 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 %}

{%trans "Info"%}

{%trans "There are currently no floating ips assigned to your tenant."%}

{% 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 similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/dash/images/_delete.html rename to 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 similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/dash/images/_form.html rename to 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 similarity index 67% rename from django-openstack/django_openstack/templates/django_openstack/dash/images/_launch.html rename to horizon/horizon/dashboards/nova/templates/nova/images/_launch.html index d0947c2386..20f48c3d4b 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 similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/dash/images/_launch_form.html rename to 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 similarity index 70% rename from django-openstack/django_openstack/templates/django_openstack/dash/images/_list.html rename to horizon/horizon/dashboards/nova/templates/nova/images/_list.html index 0a0ad21ea2..b0f25a8ddc 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 @@ diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/images/index.html b/horizon/horizon/dashboards/nova/templates/nova/images/index.html similarity index 61% rename from django-openstack/django_openstack/templates/django_openstack/dash/images/index.html rename to horizon/horizon/dashboards/nova/templates/nova/images/index.html index 421d7cf2cc..78575e906e 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 %}
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/images/launch.html b/horizon/horizon/dashboards/nova/templates/nova/images/launch.html similarity index 87% rename from django-openstack/django_openstack/templates/django_openstack/dash/images/launch.html rename to horizon/horizon/dashboards/nova/templates/nova/images/launch.html index 3501595073..2e0712006d 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 %}
- {% include 'django_openstack/dash/images/_launch.html' %} + {% include 'nova/images/_launch.html' %}

{% trans "Description:"%}

diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/images/update.html b/horizon/horizon/dashboards/nova/templates/nova/images/update.html similarity index 70% rename from django-openstack/django_openstack/templates/django_openstack/dash/images/update.html rename to horizon/horizon/dashboards/nova/templates/nova/images/update.html index 9abf192be8..d20491aaa5 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 %}
- {% include 'django_openstack/dash/images/_form.html' %} + {% include 'nova/images/_form.html' %}
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/instances/_form.html b/horizon/horizon/dashboards/nova/templates/nova/instances/_form.html similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/dash/instances/_form.html rename to 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 similarity index 68% rename from django-openstack/django_openstack/templates/django_openstack/dash/instances/_list.html rename to horizon/horizon/dashboards/nova/templates/nova/instances/_list.html index ab6c03747b..52e5180b7c 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 @@ - + {% load sizeformat %} {%load i18n%} @@ -17,7 +17,7 @@ diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/instances/detail.html b/horizon/horizon/dashboards/nova/templates/nova/instances/detail.html similarity index 89% rename from django-openstack/django_openstack/templates/django_openstack/dash/instances/detail.html rename to horizon/horizon/dashboards/nova/templates/nova/instances/detail.html index 414017f89a..0e74a7ba3c 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 @@ @@ -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 similarity index 77% rename from django-openstack/django_openstack/templates/django_openstack/dash/instances/index.html rename to horizon/horizon/dashboards/nova/templates/nova/instances/index.html index 60a2c7ab9e..9d49302f72 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 %}
- {% url dash_images request.user.tenant_id as dash_img_url %} + {% url horizon:nova:images:index as dash_img_url %}

{% trans "Info"%}

{% blocktrans %}There are currently no instances. You can launch an instance from the Images Page.{% endblocktrans %}

@@ -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 similarity index 69% rename from django-openstack/django_openstack/templates/django_openstack/dash/instances/update.html rename to horizon/horizon/dashboards/nova/templates/nova/instances/update.html index d497d2be77..85a62b64de 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 %}
- {% include 'django_openstack/dash/instances/_form.html' with form=form %} -

<< {% trans "Return to Instances List"%}

+ {% include 'nova/instances/_form.html' with form=form %} +

<< {% trans "Return to Instances List"%}

@@ -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 similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/dash/instances/usage.csv rename to 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 similarity index 88% rename from django-openstack/django_openstack/templates/django_openstack/dash/instances/usage.html rename to horizon/horizon/dashboards/nova/templates/nova/instances/usage.html index b22904402d..abc97cbbfb 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 @@

Server Usage Summary {% if show_terminated %} - ( {% trans "Hide Terminated"%} ) + ( {% trans "Hide Terminated"%} ) {% else %} - ( {% trans "Show Terminated"%} ) + ( {% trans "Show Terminated"%} ) {% endif %}

@@ -93,7 +93,7 @@
{{instance.id}} - + {{instance.name}} {% if instance.attrs.key_name %}
@@ -61,12 +61,12 @@
{{instance.status|lower|capfirst}}
{% else %}
- {% url dash_images request.user.tenant_id as dash_img_url%} + {% url horizon:nova:images:index as dash_img_url%}

{% trans "Info"%}

{% blocktrans %}There are currently no instances.

You can launch an instance from the Images Page.{% endblocktrans %}

diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/keypairs/_delete.html b/horizon/horizon/dashboards/nova/templates/nova/keypairs/_delete.html similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/dash/keypairs/_delete.html rename to 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 similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/dash/keypairs/_form.html rename to 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 similarity index 77% rename from django-openstack/django_openstack/templates/django_openstack/dash/keypairs/_list.html rename to horizon/horizon/dashboards/nova/templates/nova/keypairs/_list.html index d5288245d1..1b306949f5 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 @@ {{ keypair.fingerprint }}
    -
  • {% include "django_openstack/dash/keypairs/_delete.html" with form=delete_form %}
  • +
  • {% include "nova/keypairs/_delete.html" with form=delete_form %}
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/keypairs/create.html b/horizon/horizon/dashboards/nova/templates/nova/keypairs/create.html similarity index 76% rename from django-openstack/django_openstack/templates/django_openstack/dash/keypairs/create.html rename to horizon/horizon/dashboards/nova/templates/nova/keypairs/create.html index f6fb09aaa9..ea64d36ff4 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 %}

{% trans "Your private key is being downloaded."%}

- {% include 'django_openstack/dash/keypairs/_form.html' with form=create_form %} -

<< {% trans "Return to keypairs list"%}

+ {% include 'nova/keypairs/_form.html' with form=create_form %} +

<< {% trans "Return to keypairs list"%}

diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/keypairs/import.html b/horizon/horizon/dashboards/nova/templates/nova/keypairs/import.html similarity index 69% rename from django-openstack/django_openstack/templates/django_openstack/dash/keypairs/import.html rename to horizon/horizon/dashboards/nova/templates/nova/keypairs/import.html index 01544c6d24..0df9e20ba5 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 %}
- {% include 'django_openstack/dash/keypairs/_form.html' with form=create_form %} -

<< {% trans "Return to keypairs list"%}

+ {% include 'nova/keypairs/_form.html' with form=create_form %} +

<< {% trans "Return to keypairs list"%}

diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/keypairs/index.html b/horizon/horizon/dashboards/nova/templates/nova/keypairs/index.html similarity index 51% rename from django-openstack/django_openstack/templates/django_openstack/dash/keypairs/index.html rename to horizon/horizon/dashboards/nova/templates/nova/keypairs/index.html index ea95b8ca63..8ad9fd70d9 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' %} - {% trans "Add New Keypair"%} - {% trans "Import Keypair"%} + {% include 'nova/keypairs/_list.html' %} + {% trans "Add New Keypair"%} + {% trans "Import Keypair"%} {% else %}

{% trans "Info"%}

{% trans "There are currently no keypairs."%}

- {% trans "Add New Keypair"%} - {% trans "Import Keypair"%} + {% trans "Add New Keypair"%} + {% trans "Import Keypair"%} {% 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 similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/dash/networks/_delete.html rename to 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 similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/dash/networks/_delete_port.html rename to 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 similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/dash/networks/_detach_port.html rename to 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 similarity index 70% rename from django-openstack/django_openstack/templates/django_openstack/dash/networks/_detail.html rename to horizon/horizon/dashboards/nova/templates/nova/networks/_detail.html index 7990f4e237..b1bb51f33c 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 @@
    {% if port.attachment %} -
  • {% include "django_openstack/dash/networks/_detach_port.html" with form=detach_port_form %}
  • +
  • {% include "nova/networks/_detach_port.html" with form=detach_port_form %}
  • {% else %} -
  • {% trans "Attach"%}
  • +
  • {% trans "Attach"%}
  • {% endif %} -
  • {% include "django_openstack/dash/networks/_delete_port.html" with form=delete_port_form %}
  • -
  • {% include "django_openstack/dash/networks/_toggle_port.html" with form=toggle_port_form %}
  • +
  • {% include "nova/networks/_delete_port.html" with form=delete_port_form %}
  • +
  • {% include "nova/networks/_toggle_port.html" with form=toggle_port_form %}
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/networks/_form.html b/horizon/horizon/dashboards/nova/templates/nova/networks/_form.html similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/dash/networks/_form.html rename to 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 similarity index 65% rename from django-openstack/django_openstack/templates/django_openstack/dash/networks/_list.html rename to horizon/horizon/dashboards/nova/templates/nova/networks/_list.html index f58238226e..2e1ee13e2e 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 @@ {% for network in networks %} - {{network.id}} + {{network.id}} {{network.name}} {{network.total}} {{network.available}} {{network.used}}
    -
  • {% include "django_openstack/dash/networks/_delete.html" with form=delete_form %}
  • -
  • {% trans "Rename"%}
  • +
  • {% include "nova/networks/_delete.html" with form=delete_form %}
  • +
  • {% trans "Rename"%}
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/networks/_rename.html b/horizon/horizon/dashboards/nova/templates/nova/networks/_rename.html similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/dash/networks/_rename.html rename to 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 similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/dash/networks/_rename_form.html rename to 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 similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/dash/networks/_toggle_port.html rename to 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 similarity index 62% rename from django-openstack/django_openstack/templates/django_openstack/dash/networks/create.html rename to horizon/horizon/dashboards/nova/templates/nova/networks/create.html index 05d4aa4839..6ed8d51fa5 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 %}
- {% include 'django_openstack/dash/networks/_form.html' with form=network_form %} -

<< {% trans "Return to networks list"%}

+ {% include 'nova/networks/_form.html' with form=network_form %} +

<< {% trans "Return to networks list"%}

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 0000000000..09a3b01139 --- /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 %} + Networks »  + {{network.name}} +{% endblock %} + +{% block dash_main %} + {% if network.ports %} + {% include 'nova/networks/_detail.html' %} + {% trans "Create Ports"%} + {% else %} +
+

{% trans "Info"%}

+

{% trans "There are currently no ports in this network."%} {% trans "Create Ports"%} >>

+
+ {% 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 similarity index 56% rename from django-openstack/django_openstack/templates/django_openstack/dash/networks/index.html rename to horizon/horizon/dashboards/nova/templates/nova/networks/index.html index 16ef1eebc3..aac5d67169 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 %} {% trans "Create New Network"%} {% else %}

{% trans "Info"%}

-

{% trans "There are currently no networks."%} {% trans "Create A Network"%} >>

+

{% trans "There are currently no networks."%} {% trans "Create A Network"%} >>

{% endif %}
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/networks/rename.html b/horizon/horizon/dashboards/nova/templates/nova/networks/rename.html similarity index 67% rename from django-openstack/django_openstack/templates/django_openstack/dash/networks/rename.html rename to horizon/horizon/dashboards/nova/templates/nova/networks/rename.html index 1a63096ae7..2ec732b3b0 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 %}
- {% include 'django_openstack/dash/networks/_rename_form.html' with form=rename_form %} -

<< {% trans "Return to networks list"%}

+ {% include 'nova/networks/_rename_form.html' with form=rename_form %} +

<< {% trans "Return to networks list"%}

diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/objects/_copy.html b/horizon/horizon/dashboards/nova/templates/nova/objects/_copy.html similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/dash/objects/_copy.html rename to 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 similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/dash/objects/_delete.html rename to 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 similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/dash/objects/_filter.html rename to 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 similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/dash/objects/_form.html rename to 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 similarity index 58% rename from django-openstack/django_openstack/templates/django_openstack/dash/objects/_list.html rename to horizon/horizon/dashboards/nova/templates/nova/objects/_list.html index a73ea17722..e38ae39cc6 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 @@ {{ object.name }} diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/objects/_paging.html b/horizon/horizon/dashboards/nova/templates/nova/objects/_paging.html similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/dash/objects/_paging.html rename to 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 similarity index 63% rename from django-openstack/django_openstack/templates/django_openstack/dash/objects/copy.html rename to horizon/horizon/dashboards/nova/templates/nova/objects/copy.html index 38f5e27209..fb23f2707c 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 @@

Copy Object: '{{object_name}}'

- {% include 'django_openstack/dash/objects/_copy.html' with form=copy_form greeting="HI" %} -

<< {% trans "Return to objects list"%}

+ {% include 'nova/objects/_copy.html' with form=copy_form greeting="HI" %} +

<< {% trans "Return to objects list"%}

diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/objects/index.html b/horizon/horizon/dashboards/nova/templates/nova/objects/index.html similarity index 55% rename from django-openstack/django_openstack/templates/django_openstack/dash/objects/index.html rename to horizon/horizon/dashboards/nova/templates/nova/objects/index.html index aacefb1e65..1ddb2aa861 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 @@

Objects

- {% trans "Refresh List"%} + {% trans "Refresh List"%}
{% endblock %} @@ -23,14 +23,14 @@

Container: {{ container_name }}

{% if objects %} - {% include 'django_openstack/dash/objects/_list.html' %} + {% include 'nova/objects/_list.html' %} {% else %}
- {% 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 %}

Info

{% blocktrans %}There are currently no objects in the container {{container_name}}. You can upload a new object from the Object Upload Page >>{% endblocktrans %}

{% endif %} - {% trans "Upload New Object >>"%} + {% trans "Upload New Object >>"%} {% 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 similarity index 70% rename from django-openstack/django_openstack/templates/django_openstack/dash/objects/upload.html rename to horizon/horizon/dashboards/nova/templates/nova/objects/upload.html index 8bb7b510a0..7dfa3eb768 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 @@
- {% include 'django_openstack/dash/objects/_form.html' with form=upload_form %} -

<< {% trans "Return to objects list"%}

+ {% include 'nova/objects/_form.html' with form=upload_form %} +

<< {% trans "Return to objects list"%}

diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/ports/_attach.html b/horizon/horizon/dashboards/nova/templates/nova/ports/_attach.html similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/dash/ports/_attach.html rename to 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 similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/dash/ports/_create.html rename to 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 similarity index 76% rename from django-openstack/django_openstack/templates/django_openstack/dash/ports/attach.html rename to horizon/horizon/dashboards/nova/templates/nova/ports/attach.html index 0155bb3a11..e07871115d 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 %}
- {% include 'django_openstack/dash/ports/_attach.html' with form=attach_form %} -

<< {% trans "Return to network detail"%}

+ {% include 'nova/ports/_attach.html' with form=attach_form %} +

<< {% trans "Return to network detail"%}

diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/ports/create.html b/horizon/horizon/dashboards/nova/templates/nova/ports/create.html similarity index 62% rename from django-openstack/django_openstack/templates/django_openstack/dash/ports/create.html rename to horizon/horizon/dashboards/nova/templates/nova/ports/create.html index 381fb3d16f..629c49a16a 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 %}
- {% include 'django_openstack/dash/ports/_create.html' with form=create_form %} -

<< {% trans "Return to network detail"%}

+ {% include 'nova/ports/_create.html' with form=create_form %} +

<< {% trans "Return to network detail"%}

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 similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/dash/security_groups/_delete.html rename to 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 similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/dash/security_groups/_delete_rule.html rename to 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 similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/dash/security_groups/_form.html rename to 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 similarity index 65% rename from django-openstack/django_openstack/templates/django_openstack/dash/security_groups/_list.html rename to horizon/horizon/dashboards/nova/templates/nova/security_groups/_list.html index d8a1da57d0..7b324f1310 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 @@ {{ security_group.description }}
    -
  • {% trans "Edit Rules"%}
  • +
  • {% trans "Edit Rules"%}
  • {% if security_group.name != 'default' %} -
  • {% include "django_openstack/dash/security_groups/_delete.html" with form=delete_form %}
  • +
  • {% include "nova/security_groups/_delete.html" with form=delete_form %}
  • {% endif %}
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 similarity index 68% rename from django-openstack/django_openstack/templates/django_openstack/dash/security_groups/create.html rename to horizon/horizon/dashboards/nova/templates/nova/security_groups/create.html index 6e9d591f98..9c0bc53c8d 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 %}
- {% include 'django_openstack/dash/security_groups/_form.html' %} + {% include 'nova/security_groups/_form.html' %}
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 similarity index 87% rename from django-openstack/django_openstack/templates/django_openstack/dash/security_groups/edit_rules.html rename to horizon/horizon/dashboards/nova/templates/nova/security_groups/edit_rules.html index 3998604255..f2179103d7 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 @@ {{rule.ip_range.cidr}}
    -
  • {% include "django_openstack/dash/security_groups/_delete_rule.html" with form=delete_form %}
  • +
  • {% include "nova/security_groups/_delete_rule.html" with form=delete_form %}
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 similarity index 59% rename from django-openstack/django_openstack/templates/django_openstack/dash/security_groups/index.html rename to horizon/horizon/dashboards/nova/templates/nova/security_groups/index.html index 48e9fa496e..b266ebb79f 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 %} {% trans "Create Security Group"%} {% else %}
- {% url dash_security_groups_create request.user.tenant_id as dash_sec_url %} + {% url horizon:nova:security_groups:create as dash_sec_url %}

{% trans "Info"%}

{% blocktrans %}There are currently no security groups. Create A Security Group >>{% endblocktrans %}

diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/settings.html b/horizon/horizon/dashboards/nova/templates/nova/settings.html similarity index 85% rename from django-openstack/django_openstack/templates/django_openstack/dash/settings.html rename to horizon/horizon/dashboards/nova/templates/nova/settings.html index 658e2f5000..e770877419 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" %}
diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/snapshots/_form.html b/horizon/horizon/dashboards/nova/templates/nova/snapshots/_form.html similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/dash/snapshots/_form.html rename to 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 similarity index 66% rename from django-openstack/django_openstack/templates/django_openstack/dash/snapshots/create.html rename to horizon/horizon/dashboards/nova/templates/nova/snapshots/create.html index 2f059ab9b4..f9fcabf1c7 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 %}

{% trans "Choose a name for your snapshot."%}

- {% include 'django_openstack/dash/snapshots/_form.html' with form=create_form %} -

<< {% trans "Return to snapshots list"%}

+ {% include 'nova/snapshots/_form.html' with form=create_form %} +

<< {% trans "Return to snapshots list"%}

diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/snapshots/index.html b/horizon/horizon/dashboards/nova/templates/nova/snapshots/index.html similarity index 62% rename from django-openstack/django_openstack/templates/django_openstack/dash/snapshots/index.html rename to horizon/horizon/dashboards/nova/templates/nova/snapshots/index.html index 437a504e4f..b4e841232a 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 %}
- {% url dash_instances request.user.tenant_id as inst_url %} + {% url horizon:nova:instances:index as inst_url %}

{% trans "Info"%}

{% blocktrans %}There are currently no snapshots. You can create snapshots from running instances. View Running Instances >>{% endblocktrans %}

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 similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/dash/volumes/_attach_form.html rename to 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 similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/dash/volumes/_delete.html rename to 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 similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/dash/volumes/_detach_form.html rename to 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 similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/dash/volumes/_form.html rename to 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 similarity index 74% rename from django-openstack/django_openstack/templates/django_openstack/dash/volumes/_list.html rename to horizon/horizon/dashboards/nova/templates/nova/volumes/_list.html index 18910ff760..15935231b2 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 @@ {{ volume.id }} - + {{ volume.displayName }} @@ -24,7 +24,7 @@ {% for attachment in volume.attachments %} {% if attachment %} - + Instance {{ attachment.serverId }} ({{ attachment.device }}) @@ -39,16 +39,16 @@ {% if volume.status == "in-use" %} {% for attachment in volume.attachments %}
  • - {% include "django_openstack/dash/volumes/_detach_form.html" with form=detach_form %} + {% include "nova/volumes/_detach_form.html" with form=detach_form %}
  • {% endfor %} {% endif %} {% if volume.status == "available" %}
  • - {% trans "Attach" %} + {% trans "Attach" %}
  • - {% include "django_openstack/dash/volumes/_delete.html" with form=delete_form %} + {% include "nova/volumes/_delete.html" with form=delete_form %}
  • {% endif %} diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/volumes/attach.html b/horizon/horizon/dashboards/nova/templates/nova/volumes/attach.html similarity index 56% rename from django-openstack/django_openstack/templates/django_openstack/dash/volumes/attach.html rename to horizon/horizon/dashboards/nova/templates/nova/volumes/attach.html index ec0456f792..c762b52d68 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 %}
    - {% include 'django_openstack/dash/volumes/_attach_form.html' with form=attach_form %} -

    << {% trans "Return to volumes list" %}

    + {% include 'nova/volumes/_attach_form.html' with form=attach_form %} +

    << {% trans "Return to volumes list" %}

    diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/volumes/create.html b/horizon/horizon/dashboards/nova/templates/nova/volumes/create.html similarity index 65% rename from django-openstack/django_openstack/templates/django_openstack/dash/volumes/create.html rename to horizon/horizon/dashboards/nova/templates/nova/volumes/create.html index 9f57c8b650..4297d5d549 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 %}
    - {% include 'django_openstack/dash/volumes/_form.html' with form=create_form %} -

    << {% trans "Return to volumes list"%}

    + {% include 'nova/volumes/_form.html' with form=create_form %} +

    << {% trans "Return to volumes list"%}

    diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/volumes/detail.html b/horizon/horizon/dashboards/nova/templates/nova/volumes/detail.html similarity index 85% rename from django-openstack/django_openstack/templates/django_openstack/dash/volumes/detail.html rename to horizon/horizon/dashboards/nova/templates/nova/volumes/detail.html index edd673481f..55541636b2 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 @@
  • {% trans "Attached To:" %} {% if instance %} - + {% trans "Instance" %} {{ instance.id }} ({{ instance.name }}) diff --git a/django-openstack/django_openstack/templates/django_openstack/dash/volumes/index.html b/horizon/horizon/dashboards/nova/templates/nova/volumes/index.html similarity index 58% rename from django-openstack/django_openstack/templates/django_openstack/dash/volumes/index.html rename to horizon/horizon/dashboards/nova/templates/nova/volumes/index.html index e6fbf98317..7029e51f17 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 %}

    {% trans "Info"%}

    {% blocktrans %}There are currently no volumes.{% endblocktrans %}

    {% endif %} - {% trans "Create New Volume" %} + {% trans "Create New Volume" %} {% endblock %} diff --git a/django-openstack/django_openstack/tests/templates/base-sidebar.html b/horizon/horizon/dashboards/nova/volumes/__init__.py similarity index 100% rename from django-openstack/django_openstack/tests/templates/base-sidebar.html rename to 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 similarity index 56% rename from django-openstack/django_openstack/dash/views/volumes.py rename to horizon/horizon/dashboards/nova/volumes/forms.py index 69b225b3c3..b67d2d9246 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 0000000000..f5692e7bb9 --- /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 0000000000..e69de29bb2 diff --git a/horizon/horizon/dashboards/nova/volumes/urls.py b/horizon/horizon/dashboards/nova/volumes/urls.py new file mode 100644 index 0000000000..1e5ec42d61 --- /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[^/]+)/attach/$', 'attach', name='attach'), + url(r'^(?P[^/]+)/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 0000000000..72da94d811 --- /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 0000000000..e69de29bb2 diff --git a/horizon/horizon/dashboards/settings/dashboard.py b/horizon/horizon/dashboards/settings/dashboard.py new file mode 100644 index 0000000000..9cc88c4551 --- /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/django-openstack/django_openstack/tests/dependency_tests.py b/horizon/horizon/dashboards/settings/models.py similarity index 60% rename from django-openstack/django_openstack/tests/dependency_tests.py rename to horizon/horizon/dashboards/settings/models.py index 19df189ff4..300ba4b3f2 100644 --- a/django-openstack/django_openstack/tests/dependency_tests.py +++ b/horizon/horizon/dashboards/settings/models.py @@ -19,21 +19,5 @@ # 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. +Stub file to work around django bug: https://code.djangoproject.com/ticket/7198 """ - -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/horizon/horizon/dashboards/settings/templates/settings/base.html b/horizon/horizon/dashboards/settings/templates/settings/base.html new file mode 100644 index 0000000000..739b94c1de --- /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 %} +
    + {% include "_messages.html" %} + {% block settings_main %}{% endblock %} +
    +{% 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 0000000000..4e7fc5318f --- /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 %} + +
    +
    +

    {% trans "Dashboard User Interface Language"%}

    +
    {% csrf_token %} +

    + +
    +
    + +
     
    +
     
    +
    +{% endblock %} diff --git a/horizon/horizon/dashboards/settings/user/__init__.py b/horizon/horizon/dashboards/settings/user/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/horizon/horizon/dashboards/settings/user/panel.py b/horizon/horizon/dashboards/settings/user/panel.py new file mode 100644 index 0000000000..5f11a897b7 --- /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 0000000000..7bfddcf59c --- /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 0000000000..e69de29bb2 diff --git a/horizon/horizon/dashboards/syspanel/dashboard.py b/horizon/horizon/dashboards/syspanel/dashboard.py new file mode 100644 index 0000000000..ce4e4e0191 --- /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 0000000000..e69de29bb2 diff --git a/django-openstack/django_openstack/syspanel/views/flavors.py b/horizon/horizon/dashboards/syspanel/flavors/forms.py similarity index 56% rename from django-openstack/django_openstack/syspanel/views/flavors.py rename to horizon/horizon/dashboards/syspanel/flavors/forms.py index e15f9561c7..c79fcdbeee 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 0000000000..7a765a278f --- /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 0000000000..e69de29bb2 diff --git a/horizon/horizon/dashboards/syspanel/flavors/urls.py b/horizon/horizon/dashboards/syspanel/flavors/urls.py new file mode 100644 index 0000000000..e38603d7b8 --- /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 0000000000..7be1c1ed33 --- /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 0000000000..e69de29bb2 diff --git a/horizon/horizon/dashboards/syspanel/images/forms.py b/horizon/horizon/dashboards/syspanel/images/forms.py new file mode 100644 index 0000000000..766bd474dc --- /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 0000000000..77e7bbb01a --- /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 0000000000..e69de29bb2 diff --git a/horizon/horizon/dashboards/syspanel/images/urls.py b/horizon/horizon/dashboards/syspanel/images/urls.py new file mode 100644 index 0000000000..5df3696a12 --- /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[^/]+)/update/$', 'update', name='update')) diff --git a/django-openstack/django_openstack/syspanel/views/images.py b/horizon/horizon/dashboards/syspanel/images/views.py similarity index 65% rename from django-openstack/django_openstack/syspanel/views/images.py rename to horizon/horizon/dashboards/syspanel/images/views.py index 887581a4f0..4a998a5fd9 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 0000000000..e69de29bb2 diff --git a/horizon/horizon/dashboards/syspanel/instances/panel.py b/horizon/horizon/dashboards/syspanel/instances/panel.py new file mode 100644 index 0000000000..56b52590ca --- /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 0000000000..e69de29bb2 diff --git a/horizon/horizon/dashboards/syspanel/instances/urls.py b/horizon/horizon/dashboards/syspanel/instances/urls.py new file mode 100644 index 0000000000..369a3eb537 --- /dev/null +++ b/horizon/horizon/dashboards/syspanel/instances/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 * +from django.conf import settings + + +INSTANCES = r'^(?P[^/]+)/%s$' + + +urlpatterns = patterns('horizon.dashboards.syspanel.instances.views', + url(r'^usage/(?P[^/]+)$', '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 similarity index 64% rename from django-openstack/django_openstack/syspanel/views/instances.py rename to horizon/horizon/dashboards/syspanel/instances/views.py index b150efa440..81634b6b2a 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 0000000000..300ba4b3f2 --- /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 0000000000..e69de29bb2 diff --git a/horizon/horizon/dashboards/syspanel/overview/panel.py b/horizon/horizon/dashboards/syspanel/overview/panel.py new file mode 100644 index 0000000000..5ca5d23d38 --- /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 0000000000..614f58be83 --- /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 0000000000..e69de29bb2 diff --git a/horizon/horizon/dashboards/syspanel/quotas/panel.py b/horizon/horizon/dashboards/syspanel/quotas/panel.py new file mode 100644 index 0000000000..ede0efb421 --- /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 0000000000..e69de29bb2 diff --git a/horizon/horizon/dashboards/syspanel/quotas/urls.py b/horizon/horizon/dashboards/syspanel/quotas/urls.py new file mode 100644 index 0000000000..6f7436a8ce --- /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 similarity index 66% rename from django-openstack/django_openstack/syspanel/views/quotas.py rename to horizon/horizon/dashboards/syspanel/quotas/views.py index 816c1c8f17..73a1d4ee5a 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 0000000000..e69de29bb2 diff --git a/horizon/horizon/dashboards/syspanel/services/forms.py b/horizon/horizon/dashboards/syspanel/services/forms.py new file mode 100644 index 0000000000..81f1f673fa --- /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 0000000000..7a17f8de8a --- /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 0000000000..e69de29bb2 diff --git a/horizon/horizon/dashboards/syspanel/services/urls.py b/horizon/horizon/dashboards/syspanel/services/urls.py new file mode 100644 index 0000000000..e7757de053 --- /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 similarity index 57% rename from django-openstack/django_openstack/syspanel/views/services.py rename to horizon/horizon/dashboards/syspanel/services/views.py index c1c76a69ef..73d29ee0d4 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 similarity index 50% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/base.html rename to horizon/horizon/dashboards/syspanel/templates/syspanel/base.html index 9f5d30559c..1add065c57 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 %}
    {% 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 similarity index 68% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/flavors/_create.html rename to horizon/horizon/dashboards/syspanel/templates/syspanel/flavors/_create.html index 04f8cad953..a5bc2dd335 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 similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/flavors/_delete.html rename to 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 similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/flavors/_form.html rename to 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 similarity index 83% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/flavors/_list.html rename to horizon/horizon/dashboards/syspanel/templates/syspanel/flavors/_list.html index 05a5ddc8ae..e2fe3df23a 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 @@ {{flavor.disk}}GB
      -
    • {% include "django_openstack/syspanel/flavors/_delete.html" with form=delete_form %}
    • +
    • {% include "syspanel/flavors/_delete.html" with form=delete_form %}
    diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/flavors/create.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/flavors/create.html similarity index 87% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/flavors/create.html rename to horizon/horizon/dashboards/syspanel/templates/syspanel/flavors/create.html index 5802dda09e..c80ae35070 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 @@
    - {% include "django_openstack/syspanel/flavors/_create.html" %} + {% include "syspanel/flavors/_create.html" %}

    {% trans "Description"%}:

    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 0000000000..d1eabacf22 --- /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" %} + {% trans "Create New Flavor"%} +{% 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 similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/images/_delete.html rename to 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 similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/images/_form.html rename to 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 similarity index 82% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/images/_list.html rename to horizon/horizon/dashboards/syspanel/templates/syspanel/images/_list.html index adc85e5b0a..c3ada5015a 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 @@ {{image.status|capfirst}}
      -
    • {% include "django_openstack/syspanel/images/_delete.html" with form=delete_form %}
    • - {#
    • {% include "django_openstack/syspanel/images/_toggle.html" with form=toggle_form %}
    • #} +
    • {% include "syspanel/images/_delete.html" with form=delete_form %}
    • + {#
    • {% include "syspanel/images/_toggle.html" with form=toggle_form %}
    • #} -
    • {% trans "Edit"%}
    • +
    • {% trans "Edit"%}
    diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/images/_toggle.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/images/_toggle.html similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/images/_toggle.html rename to 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 similarity index 50% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/images/index.html rename to horizon/horizon/dashboards/syspanel/templates/syspanel/images/index.html index 9c0092cd06..a0e2943325 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 similarity index 70% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/images/update.html rename to horizon/horizon/dashboards/syspanel/templates/syspanel/images/update.html index 805c4c3c86..a9ff84ee71 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 %}
    - {% include 'django_openstack/syspanel/images/_form.html' %} + {% include 'syspanel/images/_form.html' %}
    diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/instances/_list.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/instances/_list.html similarity index 67% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/instances/_list.html rename to horizon/horizon/dashboards/syspanel/templates/syspanel/instances/_list.html index 9c20dba665..71a1304187 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 %} @@ -14,7 +14,7 @@ {% for instance in instances %} - + @@ -43,10 +43,10 @@ diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/instances/detail.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/instances/detail.html similarity index 86% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/instances/detail.html rename to horizon/horizon/dashboards/syspanel/templates/syspanel/instances/detail.html index 89d4723a64..def6e8ab0b 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 @@
    - + {% 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 similarity index 79% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/instances/index.html rename to horizon/horizon/dashboards/syspanel/templates/syspanel/instances/index.html index 228ff2dd58..3f956cc9a0 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 %}
    - {% url dash_images request.user.tenant_id as dash_image_url%} + {% url horizon:nova:images:index as dash_image_url%}

    {% trans "Info"%}

    {% blocktrans %}There are currently no instances. You can launch an instance from the Images Page.{% endblocktrans %}

    @@ -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 similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/instances/tenant_usage.csv rename to 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 similarity index 95% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/instances/tenant_usage.html rename to horizon/horizon/dashboards/syspanel/templates/syspanel/instances/tenant_usage.html index 934830d767..15a5cc7331 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 similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/instances/usage.csv rename to 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 similarity index 94% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/instances/usage.html rename to horizon/horizon/dashboards/syspanel/templates/syspanel/instances/usage.html index 905d19d7a2..de58d8a444 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 @@ {% for usage in usage_list %} - + diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/quotas/index.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/quotas/index.html similarity index 70% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/quotas/index.html rename to horizon/horizon/dashboards/syspanel/templates/syspanel/quotas/index.html index 8e4712851f..ccc90c8834 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 similarity index 93% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/services/_list.html rename to horizon/horizon/dashboards/syspanel/templates/syspanel/services/_list.html index a158c8e89f..9bda1f4c33 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 @@ diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/services/_toggle.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/services/_toggle.html similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/services/_toggle.html rename to 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 similarity index 50% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/services/index.html rename to horizon/horizon/dashboards/syspanel/templates/syspanel/services/index.html index 551e901859..b5145c71a5 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 similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/_add_user.html rename to 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 similarity index 68% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/_create_form.html rename to horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/_create_form.html index 20c58988a6..6bdae710e1 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 similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/_delete.html rename to 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 similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/_form.html rename to 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 similarity index 54% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/_list.html rename to horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/_list.html index dbd44e80aa..ac6410c468 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 @@ 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 similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/_quotas_form.html rename to 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 similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/_remove_user.html rename to 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 similarity index 68% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/_update_form.html rename to horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/_update_form.html index 5c17a8c258..5748ec0ff1 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 similarity index 66% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/_update_quotas_form.html rename to horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/_update_quotas_form.html index cfa0e6012b..5875f6ad32 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 similarity index 69% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/create.html rename to horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/create.html index d681c8bea8..0a621d69b6 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 %}
    - {% include 'django_openstack/syspanel/tenants/_create_form.html' %} + {% include 'syspanel/tenants/_create_form.html' %}
    diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/index.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/index.html similarity index 50% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/index.html rename to horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/index.html index a6d76c0788..251759ecf9 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" %} - {% trans "Create New Tenant"%} + {% include "syspanel/tenants/_list.html" %} + {% trans "Create New Tenant"%} {% 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 similarity index 62% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/quotas.html rename to horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/quotas.html index 63b865fe29..75e762cc60 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 %}
    - {% include 'django_openstack/syspanel/tenants/_update_quotas_form.html' with form=form %} + {% include 'syspanel/tenants/_update_quotas_form.html' with form=form %}

    {% trans "Description"%}:

    -

    {% trans "From here you can edit quotas (max limits) for the tenant {{tenant_id}}."%}

    +

    {% trans "From here you can edit quotas (max limits) for the tenant "%}{{ tenant_id }}.

     
    diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/update.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/update.html similarity index 68% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/update.html rename to horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/update.html index 18da7c397c..6602bac08e 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 %}
    - {% include 'django_openstack/syspanel/tenants/_update_form.html' %} + {% include 'syspanel/tenants/_update_form.html' %}
    diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/users.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/users.html similarity index 84% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/tenants/users.html rename to horizon/horizon/dashboards/syspanel/templates/syspanel/tenants/users.html index 5f7da9c2e9..6ca867e00b 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 @@
    @@ -60,7 +60,7 @@ 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 similarity index 68% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/users/_create_form.html rename to horizon/horizon/dashboards/syspanel/templates/syspanel/users/_create_form.html index 20221f230c..c55fd77d5a 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 similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/users/_delete.html rename to 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 similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/users/_enable_disable.html rename to 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 similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/users/_form.html rename to 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 similarity index 100% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/users/_toggle_enabled.html rename to 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 similarity index 68% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/users/_update_form.html rename to horizon/horizon/dashboards/syspanel/templates/syspanel/users/_update_form.html index 32117fb3be..02b77f752a 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 similarity index 73% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/users/create.html rename to horizon/horizon/dashboards/syspanel/templates/syspanel/users/create.html index c54d26cb97..f22120d387 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 %}
    - {% include 'django_openstack/syspanel/users/_create_form.html' %} + {% include 'syspanel/users/_create_form.html' %}
    diff --git a/django-openstack/django_openstack/templates/django_openstack/syspanel/users/index.html b/horizon/horizon/dashboards/syspanel/templates/syspanel/users/index.html similarity index 60% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/users/index.html rename to horizon/horizon/dashboards/syspanel/templates/syspanel/users/index.html index 4783b70b0c..0890295f6d 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 @@
    {% endfor %}
    {% trans "Name"%}
    {{instance.name}} (id: {{instance.id}}){{instance.name}} (id: {{instance.id}}) {{instance.attrs.tenant_id}} {{instance.attrs.user_id}} {{instance.attrs.host}}{{instance.status|lower|capfirst}}
    {{usage.tenant_id}}{{usage.tenant_id}} {{usage.total_active_instances}} {{usage.total_active_vcpus}} {{usage.total_active_disk_size|diskgbformat}}{{service.up}}
      -
    • {% include "django_openstack/syspanel/services/_toggle.html" with form=service_toggle_enabled_form %}
    • +
    • {% include "syspanel/services/_toggle.html" with form=service_toggle_enabled_form %}
    {{tenant.enabled}}
    {{user.email}}
      -
    • {% include "django_openstack/syspanel/tenants/_remove_user.html" with form=remove_user_form %}
    • +
    • {% include "syspanel/tenants/_remove_user.html" with form=remove_user_form %}
    {{user.name}}
      -
    • {% include "django_openstack/syspanel/tenants/_add_user.html" with form=add_user_form %}
    • +
    • {% include "syspanel/tenants/_add_user.html" with form=add_user_form %}
    {{user.tenantId}}
      -
    • {% include "django_openstack/syspanel/users/_enable_disable.html" with form=user_enable_disable_form %}
    • -
    • {% include "django_openstack/syspanel/users/_delete.html" with form=user_delete_form %}
    • -
    • {% trans "Edit"%}
    • +
    • {% include "syspanel/users/_enable_disable.html" with form=user_enable_disable_form %}
    • +
    • {% include "syspanel/users/_delete.html" with form=user_delete_form %}
    • +
    • {% trans "Edit"%}
    - {% trans "Create New User"%} + {% trans "Create New User"%}
    {% 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 similarity index 73% rename from django-openstack/django_openstack/templates/django_openstack/syspanel/users/update.html rename to horizon/horizon/dashboards/syspanel/templates/syspanel/users/update.html index 301446c5a0..6d9839fb02 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 %}
    - {% include 'django_openstack/syspanel/users/_update_form.html' %} + {% include 'syspanel/users/_update_form.html' %}
    diff --git a/horizon/horizon/dashboards/syspanel/tenants/__init__.py b/horizon/horizon/dashboards/syspanel/tenants/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/django-openstack/django_openstack/syspanel/views/tenants.py b/horizon/horizon/dashboards/syspanel/tenants/forms.py similarity index 60% rename from django-openstack/django_openstack/syspanel/views/tenants.py rename to horizon/horizon/dashboards/syspanel/tenants/forms.py index 2b7ee3abe3..e84b63da6e 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 0000000000..692a93eec0 --- /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 0000000000..e69de29bb2 diff --git a/horizon/horizon/dashboards/syspanel/tenants/urls.py b/horizon/horizon/dashboards/syspanel/tenants/urls.py new file mode 100644 index 0000000000..1e43b874f4 --- /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[^/]+)/update/$', 'update', name='update'), + url(r'^(?P[^/]+)/users/$', 'users', name='users'), + url(r'^(?P[^/]+)/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 0000000000..d6cc2735ba --- /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 0000000000..e69de29bb2 diff --git a/horizon/horizon/dashboards/syspanel/users/forms.py b/horizon/horizon/dashboards/syspanel/users/forms.py new file mode 100644 index 0000000000..4033c37ed6 --- /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 0000000000..7a7380e393 --- /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 similarity index 80% rename from django-openstack/django_openstack/tests/view_tests/syspanel/users_tests.py rename to horizon/horizon/dashboards/syspanel/users/tests.py index 9c08d12d56..7b5273e0c0 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 0000000000..2be685f927 --- /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[^/]+)/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 similarity index 51% rename from django-openstack/django_openstack/syspanel/views/users.py rename to horizon/horizon/dashboards/syspanel/users/views.py index 647e3c364d..9a1dfdadca 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. -from django import shortcuts -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.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.users') +from horizon import api +from horizon.dashboards.syspanel.users.forms import (UserForm, UserUpdateForm, + UserDeleteForm, UserEnableDisableForm) -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 0000000000..c5dc7bf2bc --- /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 0000000000..a2c621f236 --- /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 similarity index 83% rename from django-openstack/django_openstack/forms.py rename to horizon/horizon/forms.py index 201add43b7..dda6eafdbd 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 ` class which includes + processing logic in its subclasses and handling errors raised during + form processing. + + .. attribute:: method + + A :class:`CharField ` instance + rendered with a + :class:`CharField ` + 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 ` 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 similarity index 90% rename from django-openstack/django_openstack/locale/es/LC_MESSAGES/django.mo rename to horizon/horizon/locale/es/LC_MESSAGES/django.mo index 62e92be1826faa99ea2026e899d68dc630bb5e36..426ef53498f09acc66006162a63842336d93cf2f 100644 GIT binary patch delta 24 fcmZ3\n" +"Language-Team: LANGUAGE \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 Images Page." +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.

    You can launch an instance from " +"the Images Page." +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 Object Upload " +"Page >>" +msgstr "" + +#: dashboards/dash/templates/dash/objects/index.html:34 +msgid "Upload New Object >>" +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 "" +"

    Select an interface from the list on the left to attach it to this port.\n" +"

    Only interfaces that are not connected to any existing port are " +"shown

    \n" +"

    If you want to reconnect a connected interface, please detach it " +"first

    " +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. Create A " +"Security Group >>" +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. View Running Instances >>" +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 Images Page." +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 similarity index 90% rename from django-openstack/django_openstack/locale/fr/LC_MESSAGES/django.mo rename to horizon/horizon/locale/fr/LC_MESSAGES/django.mo index f444aa7409cbda9f885535c40b5964e310d8180c..b469bff6a08f16ca3917855917b9f3fdb9ac3498 100644 GIT binary patch delta 24 fcmZ3&yo7neL|#K(149KPV=Du5T?6xt^Vk>xRDK3b delta 24 fcmZ3&yo7neL|y}3BXb2q6DtE_Z3D}V^Vk>xRJsOF 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 0000000000..94a9530a13 --- /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 \n" +"Language-Team: LANGUAGE \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 Images Page." +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.

    You can launch an instance from " +"the Images Page." +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 Object Upload " +"Page >>" +msgstr "" + +#: dashboards/dash/templates/dash/objects/index.html:34 +msgid "Upload New Object >>" +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 "" +"

    Select an interface from the list on the left to attach it to this port.\n" +"

    Only interfaces that are not connected to any existing port are " +"shown

    \n" +"

    If you want to reconnect a connected interface, please detach it " +"first

    " +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. Create A " +"Security Group >>" +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. View Running Instances >>" +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 Images Page." +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 0000000000000000000000000000000000000000..59ebb9419c671becbf75eb809a832172dbc53a46 GIT binary patch literal 2528 zcmZ{kU2GIp6vwZMimQMiD&p6mR;Xsm7Goe=iWFL~y8TFLN%X}`cQ5VG-I>kY*&>NX zc1M~PEI~*`pdw<0S}lbDEocQ3dGJ9KpL{WX#LF&A{NTm-f+qgY?QORSIN3YD`QLl) zIp>};vp>z7(Z_H-h4BzZ;wHu_!10@L!!>vdW4D7JgR{YtT7L=7gZ>)44g3MT6Z{pt z3;YwD0bT=XKMAs%3DW!=+zfC&NcPWycYtfanP3#01GZ?*LHwAbwa|P`b2~`>cYzeI zPwV$U@-v`$8YKT0HNOQZ?)TuW;4dKg$!q=rlE1$|vik=t1#g2fUV9|0GDq?c>10?A*E)(zl;&>KOD@9FtBz@^Y# zAo(2ysXyOe~o&qfg_&LWWPmS|l8QhsYdvTp)uzpvLbAm!N&lHD=AJ_as; zzNq;lNdEr@$?ji}{LI2(hzmhlUkpA6mVuPF1Je24)cP<;_M@6#f#mNy5anbc47whl zfV$s@`(g~L|C1PVF(}qO7-*mJkJobQQs;+y0)x&r3xmD|%7?y->DL3(M5%s8DysJj zwSE{Z!FUYgZVal+A7j3r(4U!7bS|p-qZkGTN~XR!`mR`2%(q=fu(ckyd~UqR zx27!H(=yJgEz#cUT3+1Pz3V|ICapFO zIGbGDgl{=9Zj=b4-4aGC=Z@iXFKIgn9WN^y)K*8PgkU-+!J<~$iM1P(epu9vSt@?L zmE^3R`&(SEL$HQU?seLH3v0B5z*L+y@mAOMfdsb%XB)WX#oB>b+Oz$w#(K|9rv!9@ z$9yAdIc;fV4GlLjWWT|&QlcFWCLb{6BV~0@3)ajX%kecx>Lalh$7)S*!*`3vG)k7( zs6(lU;3>(4K%`Q^T2gU1G*r2!gszv?an>TZXQ;E%lVBU&L>ewwqvvi$=4Nf&+=zK} zBx1NJPTON0W_+@Rp(dVkJ>RSoZFbyTlWr4cvl}r&jSbDFYCkrb)kq^^EDM*HoA`yx zjb+b7!Yj=1@^Bc2W)ttUDS)uQPzFE0y+*1C?*9ptbzg~Ry#RexzJVcAZF5o@=BtAk=ZdB9FxH*=wTU*%iw@o*mLQN{(SdtrXhoEG66PFhCMQKyf8SNJAQ!W zdUjmdKfnq@pXT4)rEzuq0J}Ukc;#RhTn`|E%$}3k3&jVT+&8iI0XfW`W%*!x?(oSQ z*p~>I8Ode(^TS7ErcY+yl9}@|vrlH;m)o*8u%|Ea`ly&Ho^fJbN0!+=g)?KhoqftF zT<=$YgJGFHsdAgFQf_x|uBVsDpqJ_qbjx5wt&gz$(QM&p1}ksVK_{kz9_S&ZyAdMS z)ms=EmYEBM^W(TvlOJ+Zm*%LDOgsf1s!r->T z&>?udk~y2-aR}yT)XH9Rp~CHul-@qoF|?Ob{r`o_J4W-{kqG78r4qTI9Fc&dQ)=^c zq5FMxy!(cK3v^W7D>~t&&vwcTI(AHEdR5;J%Iw~$z7;!=KX^L-&IzP({oAr<`r7q7 af}<+yQFI68)B;lwcvn$D)DeX{%>DyylQ_o! literal 0 HcmV?d00001 diff --git a/django-openstack/django_openstack/locale/ja/LC_MESSAGES/django.po b/horizon/horizon/locale/ja/LC_MESSAGES/django.po similarity index 54% rename from django-openstack/django_openstack/locale/ja/LC_MESSAGES/django.po rename to horizon/horizon/locale/ja/LC_MESSAGES/django.po index 0a3b25d4e8..29d273b3c4 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 \n" "Language-Team: LANGUAGE \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" +#: middleware.py:85 +msgid "Your token has expired. Please log in again" +msgstr "" + +#: api/keystone.py:199 +#, fuzzy, python-format +msgid "Role does not exist: %s" +msgstr "プロジェクト%sは存在しません。" + +#: 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 +#, fuzzy +msgid "Network" +msgstr "ネットワーク" + +#: dashboards/dash/dashboard.py:29 +#, fuzzy +msgid "Object Store" 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 -#, fuzzy, 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 +#: 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 Images Page." 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.

    You can launch an instance from " "the Images Page." 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ファイル)をダウンロード" "します。これは、通常の秘密キーの様に保護した上でご使用ください。" -#: 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 >>" msgstr "" -#: templates/django_openstack/dash/objects/index.html:34 +#: dashboards/dash/templates/dash/objects/index.html:34 msgid "Upload New Object >>" 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 "" "

    Select an interface from the list on the left to attach it to this port.\n" @@ -1583,427 +1314,725 @@ msgid "" "first

    " 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. Create A " "Security Group >>" 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. View Running Instances >>" 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 "" -#: templates/django_openstack/syspanel/_sidebar.html:14 -msgid "Quotas" -msgstr "クォータ" +#: dashboards/syspanel/flavors/forms.py:49 +#, fuzzy, python-format +msgid "%s was successfully added to flavors." +msgstr "キー%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/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が更新されました。" + +#: dashboards/syspanel/services/forms.py:55 +#, fuzzy, python-format +msgid "Unable to update service '%(name)s': %(msg)s" +msgstr "インスタンス%(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 "ここより、ユーザとその資格を管理できます。" -#: 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 Images Page." 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 similarity index 89% rename from django-openstack/django_openstack/locale/pl/LC_MESSAGES/django.mo rename to horizon/horizon/locale/pl/LC_MESSAGES/django.mo index 1a8cc2afce614908b493681c2dd699f4f6112a69..94b835fdb3664261b919f73cfd9e734220a94cfd 100644 GIT binary patch delta 26 icmZ3%zJh(j8b)42T?0b}BV#KA3ta>A%{v+2GXel+8V8^N delta 26 icmZ3%zJh(j8b)3NT_bY^LlY|lV{HS=%{v+2GXel+PzRy_ diff --git a/django-openstack/django_openstack/locale/pl/LC_MESSAGES/django.po b/horizon/horizon/locale/pl/LC_MESSAGES/django.po similarity index 52% rename from django-openstack/django_openstack/locale/pl/LC_MESSAGES/django.po rename to horizon/horizon/locale/pl/LC_MESSAGES/django.po index df2d1ade72..809f629347 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 \n" "Language-Team: Polish OpenStack translations team Images Page." 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.

    You can launch an instance from " "the Images Page." 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). Należy " "chronić i używać ten klucza tak jak normalnego klucza prywantego." -#: 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 >>" msgstr "" -#: templates/django_openstack/dash/objects/index.html:34 +#: dashboards/dash/templates/dash/objects/index.html:34 msgid "Upload New Object >>" 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 "" "

    Select an interface from the list on the left to attach it to this port.\n" @@ -1580,429 +1312,722 @@ msgid "" "first

    " 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. Create A " "Security Group >>" 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. View Running Instances >>" 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 "" -#: templates/django_openstack/syspanel/_sidebar.html:14 -msgid "Quotas" +#: 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 "" -#: 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/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 "" + +#: 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 "" + +#: 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 Images Page." 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 similarity index 89% rename from django-openstack/django_openstack/locale/zh-tw/LC_MESSAGES/django.mo rename to horizon/horizon/locale/pt/LC_MESSAGES/django.mo index 8cc8b156f37599479bd55154d014d81cf1cfeef4..0e45aeca2bd41c0b9612fadd1ae60e363bcc904c 100644 GIT binary patch delta 23 fcmeyz^p9!6L|#K(149KPV=Du5T?6xp^Bw>IUHS*N delta 23 fcmeyz^p9!6L|y}3BXb2q6DtE_Z3D}R^Bw>IUNZ-} 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 0000000000..85e941a161 --- /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 \n" +"Language-Team: LANGUAGE \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 Images Page." +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.

    You can launch an instance from " +"the Images Page." +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 Object Upload " +"Page >>" +msgstr "" + +#: dashboards/dash/templates/dash/objects/index.html:34 +msgid "Upload New Object >>" +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 "" +"

    Select an interface from the list on the left to attach it to this port.\n" +"

    Only interfaces that are not connected to any existing port are " +"shown

    \n" +"

    If you want to reconnect a connected interface, please detach it " +"first

    " +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. Create A " +"Security Group >>" +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. View Running Instances >>" +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 Images Page." +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 similarity index 89% rename from django-openstack/django_openstack/locale/pt/LC_MESSAGES/django.mo rename to horizon/horizon/locale/zh-cn/LC_MESSAGES/django.mo index 8cc8b156f37599479bd55154d014d81cf1cfeef4..f2936816aabe3e9d5c093f1d0ee95203c3fba9be 100644 GIT binary patch delta 23 fcmeyz^p9!6L|#K(149KPV=Ds-T?6xp^Bw>IUI7QV delta 23 fcmeyz^p9!6L|y}3BXb2q6DtE_Z3D}R^Bw>IUNZ-} 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 0000000000..8a22933654 --- /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 \n" +"Language-Team: LANGUAGE \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 Images Page." +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.

    You can launch an instance from " +"the Images Page." +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 Object Upload " +"Page >>" +msgstr "" + +#: dashboards/dash/templates/dash/objects/index.html:34 +msgid "Upload New Object >>" +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 "" +"

    Select an interface from the list on the left to attach it to this port.\n" +"

    Only interfaces that are not connected to any existing port are " +"shown

    \n" +"

    If you want to reconnect a connected interface, please detach it " +"first

    " +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. Create A " +"Security Group >>" +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. View Running Instances >>" +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 Images Page." +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 similarity index 89% rename from django-openstack/django_openstack/locale/zh-cn/LC_MESSAGES/django.mo rename to horizon/horizon/locale/zh-tw/LC_MESSAGES/django.mo index 8cc8b156f37599479bd55154d014d81cf1cfeef4..0e45aeca2bd41c0b9612fadd1ae60e363bcc904c 100644 GIT binary patch delta 23 fcmeyz^p9!6L|#K(149KPV=Du5T?6xp^Bw>IUHS*N delta 23 fcmeyz^p9!6L|y}3BXb2q6DtE_Z3D}R^Bw>IUNZ-} 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 0000000000..85e941a161 --- /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 \n" +"Language-Team: LANGUAGE \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 Images Page." +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.

    You can launch an instance from " +"the Images Page." +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 Object Upload " +"Page >>" +msgstr "" + +#: dashboards/dash/templates/dash/objects/index.html:34 +msgid "Upload New Object >>" +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 "" +"

    Select an interface from the list on the left to attach it to this port.\n" +"

    Only interfaces that are not connected to any existing port are " +"shown

    \n" +"

    If you want to reconnect a connected interface, please detach it " +"first

    " +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. Create A " +"Security Group >>" +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. View Running Instances >>" +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 Images Page." +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 similarity index 55% rename from django-openstack/django_openstack/middleware/keystone.py rename to horizon/horizon/middleware.py index 1764371743..dfb47a7ec7 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 - -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 - - def is_admin(self): - return self.admin +from horizon import exceptions +from horizon import users -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 HorizonMiddleware(object): + """ The main Horizon middleware class. Required for use of Horizon. """ - -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 AuthenticationMiddleware(object): def process_request(self, request): - request.__class__.user = LazyUser() + """ Adds data necessary for Horizon to function to the request. + + Adds the current "active" :class:`~horizon.Dashboard` and + :class:`~horizon.Panel` to ``request.horizon``. + + 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 0000000000..300ba4b3f2 --- /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/django-openstack/django_openstack/urls.py b/horizon/horizon/site_urls.py similarity index 61% rename from django-openstack/django_openstack/urls.py rename to horizon/horizon/site_urls.py index d3b1f50539..e940a7400b 100644 --- a/django-openstack/django_openstack/urls.py +++ b/horizon/horizon/site_urls.py @@ -19,20 +19,13 @@ # 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') +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[^/]+)/$', 'switch_tenants', + name='auth_switch'),) -) - -# import urls from modules -for module_urls in dash_modules_urls.send(sender=dash_modules_urls): - urlpatterns += module_urls[1].urlpatterns +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 0000000000..b10c9a4e47 --- /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 %} +
  • + {{ component.name }} +
  • + {% 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 0000000000..5327e8eb31 --- /dev/null +++ b/horizon/horizon/templates/horizon/_subnav_list.html @@ -0,0 +1,14 @@ +{% load horizon %} + +{% for heading, panels in components.iteritems %} +

    {{ heading }}

    + +{% endfor %} diff --git a/horizon/horizon/templates/horizon/auth/_login.html b/horizon/horizon/templates/horizon/auth/_login.html new file mode 100644 index 0000000000..3c7f8abbf4 --- /dev/null +++ b/horizon/horizon/templates/horizon/auth/_login.html @@ -0,0 +1,17 @@ +{% load i18n %} +
    + {% csrf_token %} +
    + {% for hidden in form.hidden_fields %} + {{ hidden }} + {% endfor %} + {% for field in form.visible_fields %} + {{ field.label_tag }} + {{ field.errors }} + {{ field }} + {% endfor %} + {% block submit %} + + {% endblock %} +
    +
    diff --git a/django-openstack/django_openstack/templates/django_openstack/auth/_switch.html b/horizon/horizon/templates/horizon/auth/_switch.html similarity index 60% rename from django-openstack/django_openstack/templates/django_openstack/auth/_switch.html rename to horizon/horizon/templates/horizon/auth/_switch.html index af8d4d20f2..7be5450a96 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 %}
    {% csrf_token %}
    {% 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 %} - + {% endblock %}
    diff --git a/django-openstack/django_openstack/templates/django_openstack/common/_page_header.html b/horizon/horizon/templates/horizon/common/_page_header.html similarity index 70% rename from django-openstack/django_openstack/templates/django_openstack/common/_page_header.html rename to horizon/horizon/templates/horizon/common/_page_header.html index 277c289b6e..2819921841 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 %} {% endif %}
    diff --git a/horizon/horizon/templates/horizon/common/_sidebar.html b/horizon/horizon/templates/horizon/common/_sidebar.html new file mode 100644 index 0000000000..a9b06adae1 --- /dev/null +++ b/horizon/horizon/templates/horizon/common/_sidebar.html @@ -0,0 +1,5 @@ +{% load horizon i18n %} + + diff --git a/django-openstack/django_openstack/templates/django_openstack/common/_sidebar_module.html b/horizon/horizon/templates/horizon/common/_sidebar_module.html similarity index 66% rename from django-openstack/django_openstack/templates/django_openstack/common/_sidebar_module.html rename to horizon/horizon/templates/horizon/common/_sidebar_module.html index 661108dc71..2b9739ce1c 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 %} -

    {{module.title}}

    +

    {{ module.title }}

    {% 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 0000000000..2fa3e53720 --- /dev/null +++ b/horizon/horizon/templates/horizon/common/instances/_reboot.html @@ -0,0 +1,9 @@ +{% load i18n %} +
    + {% csrf_token %} + {% for hidden in form.hidden_fields %} + {{ hidden }} + {% endfor %} + + +
    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 0000000000..054c64ea9c --- /dev/null +++ b/horizon/horizon/templates/horizon/common/instances/_terminate.html @@ -0,0 +1,9 @@ +{% load i18n %} +
    + {% csrf_token %} + {% for hidden in form.hidden_fields %} + {{ hidden }} + {% endfor %} + + +
    diff --git a/horizon/horizon/templatetags/__init__.py b/horizon/horizon/templatetags/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/django-openstack/django_openstack/templatetags/templatetags/branding.py b/horizon/horizon/templatetags/branding.py similarity index 97% rename from django-openstack/django_openstack/templatetags/templatetags/branding.py rename to horizon/horizon/templatetags/branding.py index 79e5a91d56..d62c79bd4a 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 0000000000..9df91a80c5 --- /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 similarity index 100% rename from django-openstack/django_openstack/templatetags/templatetags/parse_date.py rename to horizon/horizon/templatetags/parse_date.py diff --git a/django-openstack/django_openstack/templatetags/templatetags/sizeformat.py b/horizon/horizon/templatetags/sizeformat.py similarity index 100% rename from django-openstack/django_openstack/templatetags/templatetags/sizeformat.py rename to 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 0000000000..5c79c4c1e2 --- /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 similarity index 100% rename from django-openstack/django_openstack/templatetags/templatetags/truncate_filter.py rename to horizon/horizon/templatetags/truncate_filter.py diff --git a/horizon/horizon/test.py b/horizon/horizon/test.py new file mode 100644 index 0000000000..97f512aff0 --- /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('

    ' + 'This is a fake httpresponse for testing purposes only' + '

    ') + + # 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 similarity index 95% rename from django-openstack/django_openstack/tests/__init__.py rename to horizon/horizon/tests/__init__.py index 8dc4fb673c..31e69bd4ab 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 0000000000..b3fc6e5bd7 --- /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 0000000000..71daae4fec --- /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 0000000000..dea27d1228 --- /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 0000000000..3af463f325 --- /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 0000000000..92dac4aed2 --- /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 0000000000..77c667e0aa --- /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 0000000000..37dcd2b375 --- /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 similarity index 84% rename from django-openstack/django_openstack/tests/view_tests/auth_tests.py rename to horizon/horizon/tests/auth_tests.py index 1c637f2747..50333f12da 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 0000000000..fbef314932 --- /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(), + ['', + '', + '', + '']) + + # 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), "") + 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'], + ['', + '', + '', + '', + '', + '', + '', + '']) + 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'], + ['']) + + # 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(), + ['', + '']) + + 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 0000000000..b4e507d12a --- /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 0000000000..e69de29bb2 diff --git a/horizon/horizon/tests/templates/base.html b/horizon/horizon/tests/templates/base.html new file mode 100644 index 0000000000..e69de29bb2 diff --git a/horizon/horizon/tests/templates/splash.html b/horizon/horizon/tests/templates/splash.html new file mode 100644 index 0000000000..e69de29bb2 diff --git a/horizon/horizon/tests/templates/switch_tenants.html b/horizon/horizon/tests/templates/switch_tenants.html new file mode 100644 index 0000000000..e69de29bb2 diff --git a/openstack-dashboard/dashboard/tests.py b/horizon/horizon/tests/templatetag_tests.py similarity index 60% rename from openstack-dashboard/dashboard/tests.py rename to horizon/horizon/tests/templatetag_tests.py index a723105678..d05c7d894e 100644 --- a/openstack-dashboard/dashboard/tests.py +++ b/horizon/horizon/tests/templatetag_tests.py @@ -18,21 +18,21 @@ # License for the specific language governing permissions and limitations # under the License. -''' Test for django mailer. +import re -This test is pretty much worthless, and should be removed once real testing of -views that send emails is implemented -''' +from django import dispatch, http, template +from django.utils.text import normalize_newlines -from django import test -from django.core import mail -from mailer import engine -from mailer import send_mail +from horizon import test -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') +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 similarity index 59% rename from django-openstack/django_openstack/tests/testsettings.py rename to horizon/horizon/tests/testsettings.py index 3765701569..145f216573 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') -ROOT_URLCONF = 'django_openstack.tests.testurls' -TEMPLATE_DIRS = ( - os.path.join(ROOT_PATH, 'tests', 'templates') -) +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 = '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/django-openstack/django_openstack/tests/testurls.py b/horizon/horizon/tests/testurls.py similarity index 63% rename from django-openstack/django_openstack/tests/testurls.py rename to horizon/horizon/tests/testurls.py index 4dc34d9f96..21fa7e368d 100644 --- a/django-openstack/django_openstack/tests/testurls.py +++ b/horizon/horizon/tests/testurls.py @@ -19,22 +19,15 @@ # under the License. """ -URL patterns for testing django-openstack views. +URL patterns for testing Horizon views. """ from django.conf.urls.defaults import * -from django_openstack import urls as django_openstack_urls +import horizon 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') + url(r'^$', 'horizon.tests.views.fakeView', name='splash'), + url(r'', include(horizon.urls)), ) - - -# NOTE(termie): just append them since we want the routes at the root -urlpatterns += django_openstack_urls.urlpatterns diff --git a/django-openstack/django_openstack/tests/views.py b/horizon/horizon/tests/views.py similarity index 100% rename from django-openstack/django_openstack/tests/views.py rename to horizon/horizon/tests/views.py diff --git a/horizon/horizon/users.py b/horizon/horizon/users.py new file mode 100644 index 0000000000..a3b880c135 --- /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 similarity index 100% rename from django-openstack/django_openstack/version.py rename to horizon/horizon/version.py diff --git a/horizon/horizon/views/__init__.py b/horizon/horizon/views/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/django-openstack/django_openstack/auth/views.py b/horizon/horizon/views/auth.py similarity index 89% rename from django-openstack/django_openstack/auth/views.py rename to horizon/horizon/views/auth.py index 73dc762272..9322b04914 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 0000000000..7664b69402 --- /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 old mode 100755 new mode 100644 similarity index 87% rename from django-openstack/setup.py rename to horizon/setup.py index 2e3f46c0ac..66644ec581 --- 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 3c9053a212..f902e97db8 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 ------------------------------------- +Settings Up OpenStack +===================== -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 +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/openstackx - -and add the following option to your nova instantiation: - -> --osapi_extensions_path=/path/to/openstackx/extensions - -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 - -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 95d004932a..73053f395c 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 d0678953bc..6a8772f79b 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 5c43e5492a..1b5100be2e 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 0000000000000000000000000000000000000000..f3b9bf9c440bad810cf0508569216543bb96bf11 GIT binary patch literal 1150 zcmb``T}V?=00;0Z^jxCtqdT|VeYwrKHC@=MrDj-^FGe2(JtRF@5Y$6vSPCXRq}ie* z5Gt@t5g&Tclxb3_HYMFl|oUQl>_suD^JebAf{;zoM zpU3Mr-!buFiTOOUjD-b}q{4{ij}^O-%->;@IvNcNGJW3fKk5XCUk95swY z;fBpViu^tC`IGo_&=?z;&0AmMa_!_Fd9$M$)LKayc?LIj?ro3Vqq9~)Z*F0>=LX5x zA)GutiHgc8xNpp$;odB4S&fX&+zeOFD2^PRh~*_@{aRBKL-YUQ%6W&v1OG2C6E2bc z*2)+xy)at)VX=E*b&!3U<;Nyx08ZBkL+8%U8^iv??_=xFE9i#7*2U;7T@XxUj~Y5b z_pMxLhg|)uHl*m<&^Iu}^3i{AZhjfm^z;%!6Y~fR&%x{ag6=0XxZgU7n(HCvRA~Uc L&mvil16JcFha9?* literal 0 HcmV?d00001 diff --git a/openstack-dashboard/dashboard/templates/_login.html b/openstack-dashboard/dashboard/templates/_login.html index c2a1ead9b6..db15f93840 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 %} diff --git a/openstack-dashboard/dashboard/templates/_switch.html b/openstack-dashboard/dashboard/templates/_switch.html index 9b6004ae22..6994583285 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 %} diff --git a/openstack-dashboard/dashboard/templates/_topbar.html b/openstack-dashboard/dashboard/templates/_topbar.html index ea1729e9ea..b75d38a51a 100644 --- a/openstack-dashboard/dashboard/templates/_topbar.html +++ b/openstack-dashboard/dashboard/templates/_topbar.html @@ -1,21 +1,14 @@ -{%load i18n%} +{% load horizon i18n %} + diff --git a/openstack-dashboard/dashboard/templates/base.html b/openstack-dashboard/dashboard/templates/base.html index 97f92dde05..ab136e19e0 100644 --- a/openstack-dashboard/dashboard/templates/base.html +++ b/openstack-dashboard/dashboard/templates/base.html @@ -13,6 +13,7 @@ + {% block headerjs %}{% endblock %} {% block headercss %}{% endblock %} diff --git a/openstack-dashboard/dashboard/templates/switch_tenants.html b/openstack-dashboard/dashboard/templates/switch_tenants.html index e19a973994..f00664312c 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 %} @@ -9,7 +9,7 @@
    -

    {% trans "Log-in to tenant"%}: {{to_tenant}}

    +

    {% trans "Log-in to tenant"%}: {{ to_tenant }}


    {% include "_messages.html" %} {% include '_login.html' %} diff --git a/openstack-dashboard/dashboard/urls.py b/openstack-dashboard/dashboard/urls.py index 1f2c6bd9a0..ed60acc559 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 0d7fab079e..fb06c62d33 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 b6063244c0..ceebde779f 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 37c35c3333..50195979eb 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 1ac5a74cb3..17c3481cd3 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 9129964706..51efe29fd4 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 94950878f1..89e021d8f2 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