Retire astara repo

Retire repository, following
https://docs.openstack.org/infra/manual/drivers.html#retiring-a-project

Change-Id: Ife1a293edd8889ebd36fbfe393978aec57b660fe
This commit is contained in:
Andreas Jaeger 2018-10-14 12:54:04 +02:00
parent 9b1243fdc0
commit 9b88ba7299
42 changed files with 10 additions and 1438 deletions

36
.gitignore vendored
View File

@ -1,36 +0,0 @@
*.py[co]
# Packages
*.egg
*.egg-info
dist
build
eggs
parts
bin
var
sdist
develop-eggs
.installed.cfg
# Installer logs
pip-log.txt
# Unit test / coverage reports
.coverage
.tox
#Translations
*.mo
#Mr Developer
.mr.developer.cfg
# Packaging output
*.deb
# pbr output
AUTHORS
ChangeLog
test.conf

View File

@ -1,21 +0,0 @@
# Astara Horizon Extension
1. Install module
```
pip install astara-horizon
```
2. Copy extension files from the project root folder to ```/etc/openstack_dashboard/local/enabled``` or to ```/opt/stack/horizon/openstack_dashboard/local/enabled``` folder
```
cp openstack_dashboard_extensions/*.py /opt/stack/horizon/openstack_dashboard/local/enabled/
```
3. Specify rug management prefix, rug api port, and router image uuid in ```local_setting.py```
```
RUG_MANAGEMENT_PREFIX = "fdca:3ba5:a17a:acda::/64"
RUG_API_PORT = 44250
ROUTER_IMAGE_UUID = "1e9c16f3-e070-47b7-b49c-ffcf38df5f9a"
```

10
README.rst Normal file
View File

@ -0,0 +1,10 @@
This project is no longer maintained.
The contents of this repository are still available in the Git
source code management system. To see the contents of this
repository before it reached its end of life, please check out the
previous commit with "git checkout HEAD^1".
For any further questions, please email
openstack-dev@lists.openstack.org or join #openstack-dev on
Freenode.

View File

@ -1,35 +0,0 @@
# Copyright 2014 DreamHost, LLC
#
# Author: DreamHost, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
# Copyright 2014 DreamHost, LLC
#
# Author: DreamHost, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
__import__('pkg_resources').declare_namespace(__name__)

View File

@ -1,138 +0,0 @@
# Copyright (c) 2015 Akanda, Inc. 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.
from datetime import datetime
from django.conf import settings
from horizon.utils import functions as utils
import requests as r
from openstack_dashboard.api import base
from openstack_dashboard.api.nova import novaclient
from openstack_dashboard.api.neutron import neutronclient
KEYSTONE_SERVICE_NAME = 'astara'
class Router(object):
id = ''
name = ''
status = ''
latest = ''
image_name = ''
last_fetch = ''
booted = ''
def __init__(self, **kw):
for k, v in kw.items():
setattr(self, k, v)
class AstaraClient(object):
def __init__(self):
self.image_uuid = settings.ROUTER_IMAGE_UUID
self.api_limit = getattr(settings, 'API_RESULT_LIMIT', 1000)
def _make_request(self, request, path):
url = base.url_for(request, KEYSTONE_SERVICE_NAME) + path
try:
return r.put(url).ok
except r.RequestException:
return False
def poll(self, request):
path = '/poll'
return self._make_request(request, path)
def config_reload(self, request):
path = '/config/reload'
return self._make_request(request, path)
def workers_debug(self, request):
path = '/workers/debug'
return self._make_request(request, path)
def router_debug(self, request, router_id):
path = '/router/debug/{router_id}'.format(router_id=router_id)
return self._make_request(request, path)
def router_manage(self, request, router_id):
path = '/router/manage/{router_id}'.format(router_id=router_id)
return self._make_request(request, path)
def router_update(self, request, router_id):
path = '/router/update/{router_id}'.format(router_id=router_id)
return self._make_request(request, path)
def router_rebuild(self, request, router_id, router_image_uuid=None):
if router_image_uuid:
path = ('/router/rebuild/{router_id}/--router_image_uuid/' +
'{router_image_uuid}').format(
router_id=router_id,
router_image_uuid=router_image_uuid
)
else:
path = '/router/rebuild/{router_id}/'.format(router_id=router_id)
return self._make_request(request, path)
def tenant_debug(self, request, tenant_id):
path = '/tenant/debug/{tenant_id}'.format(tenant_id=tenant_id)
return self._make_request(request, path)
def tenant_manage(self, request, tenant_id):
path = '/tenant/manage/{tenant_id}'.format(tenant_id=tenant_id)
return self._make_request(request, path)
def get_routers(self, request, **search_opts):
page_size = utils.get_page_size(request)
paginate = False
if 'paginate' in search_opts:
paginate = search_opts.pop('paginate')
search_opts['limit'] = page_size + 1
if 'tenant_id' not in search_opts:
search_opts['all_tenants'] = True
routers_metadata = []
nova_client = novaclient(request)
routers = (
neutronclient(request)
.list_routers(**search_opts)
.get("routers", [])
)
for router in routers:
search_opts = {'name': 'ak-' + router['id'], 'all_tenants': True}
instances = nova_client.servers.list(True, search_opts=search_opts)
instance = instances[0] if instances else None
image = (
nova_client.images.get(instance.image['id'])
if instance else None
)
routers_metadata.append(Router(
id=router['id'],
name=router['name'],
latest=image.id == self.image_uuid if image else '',
image_name=image.name if image else '',
last_fetch=datetime.utcnow(),
booted=instance.created if instance else '',
status=router['status'],
tenant_id=router['tenant_id'],
))
has_more_data = False
if paginate and len(routers_metadata) > page_size:
routers_metadata.pop(-1)
has_more_data = True
elif paginate and len(routers_metadata) == self.api_limit:
has_more_data = True
return routers_metadata, has_more_data

View File

@ -1,82 +0,0 @@
# Copyright (c) 2015 Akanda, Inc. 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.
from django.utils.translation import ugettext_lazy as _
from django.template.defaultfilters import filesizeformat
from horizon import exceptions
from horizon import forms
from horizon import messages
from openstack_dashboard.dashboards.project.images import utils
from astara_horizon.astara_openstack_dashboard.api.astara import AstaraClient
rc = AstaraClient()
def _image_choice_title(img):
gb = filesizeformat(img.size)
return '%s (%s)' % (img.name or img.id, gb)
class PollForm(forms.SelfHandlingForm):
def handle(self, request, data):
try:
rc.poll(request)
messages.success(request, _('Routers were polled'))
except Exception:
exceptions.handle(request, _('Unable to poll routers.'))
return True
class RebuildForm(forms.SelfHandlingForm):
router_id = forms.CharField(label=_("ID"),
widget=forms.HiddenInput(),
required=True)
router_name = forms.CharField(label=_("Router Name"),
widget=forms.HiddenInput(),
required=False)
attrs = {'class': 'image-selector'}
image = forms.ChoiceField(label=_("Select Image"),
widget=forms.SelectWidget(attrs=attrs,
data_attrs=('size', 'display-name'),
transform=_image_choice_title),
required=False)
def __init__(self, request, *args, **kwargs):
super(RebuildForm, self).__init__(request, *args, **kwargs)
images = utils.get_available_images(request, request.user.tenant_id)
choices = [(image.id, image) for image in images]
if choices:
choices.insert(0, ("", _("Select Image")))
else:
choices.insert(0, ("", _("No images available")))
self.fields['image'].choices = choices
def handle(self, request, data):
try:
if data['image']:
rc.router_rebuild(request, data['router_id'], data['image'])
else:
rc.router_rebuild(request, data['router_id'])
messages.success(request,
_('Rebuilt Router: %s.') % data['router_name'])
except Exception:
exceptions.handle(
request,
_('Unable to rebuild router %s.' % data['router_name'])
)
return True

View File

@ -1,17 +0,0 @@
# Copyright (c) 2015 Akanda, Inc. 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.
"""
Stub file to work around django bug: https://code.djangoproject.com/ticket/7198
"""

View File

@ -1,27 +0,0 @@
# Copyright (c) 2015 Akanda, Inc. 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.
from django.utils.translation import ugettext_lazy as _
import horizon
from openstack_dashboard.dashboards.admin import dashboard
class AstaraRouters(horizon.Panel):
name = _("Routers")
slug = "astararouters"
dashboard.Admin.register(AstaraRouters)

View File

@ -1,151 +0,0 @@
# Copyright (c) 2015 Akanda, Inc. 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.
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ungettext_lazy
from horizon import exceptions
from horizon import tables
from astara_horizon.astara_openstack_dashboard.api.astara import AstaraClient
rc = AstaraClient()
class ManageAction(tables.BatchAction):
name = "manage"
def get_default_classes(self):
classes = super(tables.BatchAction, self).get_default_classes()
classes += ("btn-danger", )
return classes
@staticmethod
def action_present(count):
return ungettext_lazy(
u"Manage Router",
u"Manage Routers",
count
)
@staticmethod
def action_past(count):
return ungettext_lazy(
u"Managed Router",
u"Managed Routers",
count
)
def action(self, request, obj_id):
try:
rc.router_manage(request, obj_id)
except Exception:
msg = _('Failed to manage route %s') % obj_id
exceptions.handle(request, msg)
class DebugAction(tables.BatchAction):
name = "debug"
def get_default_classes(self):
classes = super(tables.BatchAction, self).get_default_classes()
classes += ("btn-danger", )
return classes
@staticmethod
def action_present(count):
return ungettext_lazy(
u"Debug Router",
u"Debug Routers",
count
)
@staticmethod
def action_past(count):
return ungettext_lazy(
u"Debugged Router",
u"Debugged Routers",
count
)
def action(self, request, obj_id):
try:
rc.router_debug(request, obj_id)
except Exception:
msg = _('Failed to manage route %s') % obj_id
exceptions.handle(request, msg)
class UpdateAction(tables.BatchAction):
name = "update"
def get_default_classes(self):
classes = super(tables.BatchAction, self).get_default_classes()
classes += ("btn-danger", )
return classes
@staticmethod
def action_present(count):
return ungettext_lazy(
u"Update Router",
u"Update Routers",
count
)
@staticmethod
def action_past(count):
return ungettext_lazy(
u"Updated Router",
u"Updated Routers",
count
)
def action(self, request, obj_id):
try:
rc.router_update(request, obj_id)
except Exception:
msg = _('Failed to manage route %s') % obj_id
exceptions.handle(request, msg)
class PollAction(tables.LinkAction):
name = "poll"
verbose_name = _("Poll Routers")
url = "horizon:admin:astararouters:poll"
classes = ("ajax-modal",)
class RebuildAction(tables.LinkAction):
name = "rebuild"
verbose_name = _("Rebuild Router")
url = "horizon:admin:astararouters:rebuild"
classes = ("ajax-modal",)
class RouterTable(tables.DataTable):
name = tables.Column("name", verbose_name=_("Name"),
link="horizon:admin:routers:detail")
status = tables.Column("status", verbose_name=_("Status"))
latest = tables.Column('latest', verbose_name=_("Latest"))
image_name = tables.Column('image_name', verbose_name=_("Image Name"))
last_fetch = tables.Column('last_fetch', verbose_name=_("Last Fetch"))
booted = tables.Column('booted', verbose_name=_("Booted"))
class Meta:
name = "routers"
verbose_name = _("Routers")
table_actions = (ManageAction, DebugAction, PollAction)
status_columns = ('status',)
row_actions = (RebuildAction, UpdateAction, ManageAction, DebugAction,)

View File

@ -1,21 +0,0 @@
{% extends "horizon/common/_modal_form.html" %}
{% load i18n %}
{% load url from future %}
{% block form_id %}poll_astararouters_form{% endblock %}
{% block form_action %}{% url 'horizon:admin:astararouters:poll' %}{% endblock %}
{% block modal_id %}poll_astararouters_modal{% endblock %}
{% block modal-header %}{% trans "Poll Routers" %}{% endblock %}
{% block modal-body %}
<div class="right">
<p>{% trans "All routers will be polled" %}</p>
</div>
{% endblock %}
{% block modal-footer %}
<input class="btn btn-primary" type="submit" value="{% trans "Poll Routers" %}" />
<a href="{% url 'horizon:admin:astararouters:index' %}" class="btn btn-default cancel">{% trans "Cancel" %}</a>
{% endblock %}

View File

@ -1,27 +0,0 @@
{% extends "horizon/common/_modal_form.html" %}
{% load i18n %}
{% load url from future %}
{% block form_id %}rebuild_astararouters_form{% endblock %}
{% block form_action %}{% url 'horizon:admin:astararouters:rebuild' router_id %}{% endblock %}
{% block modal_id %}rebuild_astararouters_modal{% endblock %}
{% block modal-header %}{% trans "Rebuild Router" %}{% endblock %}
{% block modal-body %}
<div class="left">
<fieldset>
{% include "horizon/common/_form_fields.html" %}
</fieldset>
</div>
<div class="right">
<h3>{% trans "Description" %}:</h3>
<p>{% trans "Choose image to rebuild router" %}</p>
</div>
{% endblock %}
{% block modal-footer %}
<input class="btn btn-primary" type="submit" value="{% trans "Rebuild Router" %}" />
<a href="{% url 'horizon:admin:astararouters:index' %}" class="btn btn-default cancel">{% trans "Cancel" %}</a>
{% endblock %}

View File

@ -1,17 +0,0 @@
{% extends 'base.html' %}
{% load i18n %}
{% block title %}{% trans "Routers" %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=_("Routers") %}
{% endblock page_header %}
{% block main %}
<div class="row">
<div class="col-sm-12">
{{ table.render }}
</div>
</div>
{% endblock %}

View File

@ -1,11 +0,0 @@
{% extends 'base.html' %}
{% load i18n %}
{% block title %}{% trans "Poll Routers" %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=_("Poll Routers") %}
{% endblock page_header %}
{% block main %}
{% include "admin/astararouters/_poll.html" %}
{% endblock %}

View File

@ -1,11 +0,0 @@
{% extends 'base.html' %}
{% load i18n %}
{% block title %}{% trans "Rebuild Router" %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=_("Rebuild Router") %}
{% endblock page_header %}
{% block main %}
{% include "admin/astararouters/_rebuild.html" %}
{% endblock %}

View File

@ -1,28 +0,0 @@
# Copyright (c) 2015 Akanda, Inc. 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.
from django.conf.urls import patterns
from django.conf.urls import url
from astara_horizon.astara_openstack_dashboard.dashboards.admin.astararouters \
import views
ROUTERS = r'^(?P<router_id>[^/]+)/%s$'
urlpatterns = patterns(
'rug_openstack_dashboard.dashboards.admin.astararouters.views',
url(r'^$', views.IndexView.as_view(), name='index'),
url(r'^poll$', views.PollView.as_view(), name='poll'),
url(ROUTERS % 'rebuild', views.RebuildView.as_view(), name='rebuild'),
)

View File

@ -1,79 +0,0 @@
# Copyright (c) 2015 Akanda, Inc. 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.
from django.core.urlresolvers import reverse
from django.core.urlresolvers import reverse_lazy
from django.utils.translation import ugettext_lazy as _
from horizon import tables
from horizon import forms
from horizon import exceptions
from openstack_dashboard import api
from astara_horizon.astara_openstack_dashboard.dashboards.admin.astararouters \
import tables as router_tables
from astara_horizon.astara_openstack_dashboard.dashboards.admin.astararouters \
import forms as astararouters_forms
from astara_horizon.astara_openstack_dashboard.api.astara import AstaraClient
rc = AstaraClient()
class IndexView(tables.DataTableView):
table_class = router_tables.RouterTable
template_name = 'admin/astararouters/index.html'
def has_prev_data(self, table):
return getattr(self, "_prev", False)
def has_more_data(self, table):
return getattr(self, "_more", False)
def get_data(self):
try:
routers, self._more = rc.get_routers(self.request)
return routers
except Exception:
url = reverse('horizon:admin:astararouters:index')
exceptions.handle(self.request,
_('Unable to retrieve routers\' details.'),
redirect=url)
class PollView(forms.ModalFormView):
form_class = astararouters_forms.PollForm
template_name = 'admin/astararouters/poll.html'
success_url = reverse_lazy('horizon:admin:astararouters:index')
class RebuildView(forms.ModalFormView):
form_class = astararouters_forms.RebuildForm
template_name = 'admin/astararouters/rebuild.html'
success_url = reverse_lazy('horizon:admin:astararouters:index')
def get_context_data(self, **kwargs):
self.router = api.neutron.router_get(self.request,
self.kwargs['router_id'])
context = super(RebuildView, self).get_context_data(**kwargs)
context["router_id"] = self.kwargs['router_id']
context["router_name"] = self.router['name']
return context
def get_initial(self):
return {
'router_id': self.kwargs['router_id'],
'router_name': self.get_context_data()['router_name']
}

View File

@ -1,17 +0,0 @@
# Copyright (c) 2015 Akanda, Inc. 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.
"""
Stub file to work around django bug: https://code.djangoproject.com/ticket/7198
"""

View File

@ -1,27 +0,0 @@
# Copyright (c) 2015 Akanda, Inc. 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.
from django.utils.translation import ugettext_lazy as _
import horizon
from openstack_dashboard.dashboards.admin import dashboard
class AstaraTenants(horizon.Panel):
name = _("Tenants")
slug = "astaratenants"
dashboard.Admin.register(AstaraTenants)

View File

@ -1,242 +0,0 @@
# Copyright (c) 2015 Akanda, Inc. 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.
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import ungettext_lazy
from horizon import tables
from horizon import exceptions
from astara_horizon.astara_openstack_dashboard.api.astara import AstaraClient
rc = AstaraClient()
class TenantFilterAction(tables.FilterAction):
def filter(self, table, tenants, filter_string):
q = filter_string.lower()
def comp(tenant):
if q in tenant.name.lower():
return True
return False
return filter(comp, tenants)
class TenantManageAction(tables.BatchAction):
name = "manage"
def get_default_classes(self):
classes = super(tables.BatchAction, self).get_default_classes()
classes += ("btn-danger", )
return classes
@staticmethod
def action_present(count):
return ungettext_lazy(
u"Manage Tenant",
u"Manage Tenants",
count
)
@staticmethod
def action_past(count):
return ungettext_lazy(
u"Managed Tenant",
u"Managed Tenants",
count
)
def action(self, request, obj_id):
try:
rc.tenant_manage(request, obj_id)
except Exception:
msg = _('Failed to manage route %s') % obj_id
exceptions.handle(request, msg)
class TenantDebugAction(tables.BatchAction):
name = "debug"
def get_default_classes(self):
classes = super(tables.BatchAction, self).get_default_classes()
classes += ("btn-danger", )
return classes
@staticmethod
def action_present(count):
return ungettext_lazy(
u"Debug Tenant",
u"Debug Tenants",
count
)
@staticmethod
def action_past(count):
return ungettext_lazy(
u"Debugged Tenant",
u"Debugged Tenants",
count
)
def action(self, request, obj_id):
try:
rc.tenant_debug(request, obj_id)
except Exception:
msg = _('Failed to manage route %s') % obj_id
exceptions.handle(request, msg)
class TenantsTable(tables.DataTable):
name = tables.Column('name', verbose_name=_('Name'),
link="horizon:admin:astaratenants:tenant")
description = tables.Column(lambda obj: getattr(obj, 'description', None),
verbose_name=_('Description'))
id = tables.Column('id', verbose_name=_('Project ID'))
enabled = tables.Column('enabled', verbose_name=_('Enabled'), status=True)
class Meta:
name = "tenants"
verbose_name = _("Tenants")
row_actions = (TenantDebugAction, TenantManageAction, )
table_actions = (TenantFilterAction, )
pagination_param = "tenant_marker"
class RouterManageAction(tables.BatchAction):
name = "manage"
def get_default_classes(self):
classes = super(tables.BatchAction, self).get_default_classes()
classes += ("btn-danger", )
return classes
@staticmethod
def action_present(count):
return ungettext_lazy(
u"Manage Router",
u"Manage Routers",
count
)
@staticmethod
def action_past(count):
return ungettext_lazy(
u"Managed Router",
u"Managed Routers",
count
)
def action(self, request, obj_id):
try:
rc.router_manage(request, obj_id)
except Exception:
msg = _('Failed to manage route %s') % obj_id
exceptions.handle(request, msg)
class RouterDebugAction(tables.BatchAction):
name = "debug"
def get_default_classes(self):
classes = super(tables.BatchAction, self).get_default_classes()
classes += ("btn-danger", )
return classes
@staticmethod
def action_present(count):
return ungettext_lazy(
u"Debug Router",
u"Debug Routers",
count
)
@staticmethod
def action_past(count):
return ungettext_lazy(
u"Debugged Router",
u"Debugged Routers",
count
)
def action(self, request, obj_id):
try:
rc.router_debug(request, obj_id)
except Exception:
msg = _('Failed to manage route %s') % obj_id
exceptions.handle(request, msg)
class RouterUpdateAction(tables.BatchAction):
name = "update"
def get_default_classes(self):
classes = super(tables.BatchAction, self).get_default_classes()
classes += ("btn-danger", )
return classes
@staticmethod
def action_present(count):
return ungettext_lazy(
u"Update Router",
u"Update Routers",
count
)
@staticmethod
def action_past(count):
return ungettext_lazy(
u"Updated Router",
u"Updated Routers",
count
)
def action(self, request, obj_id):
try:
rc.router_update(request, obj_id)
except Exception:
msg = _('Failed to manage route %s') % obj_id
exceptions.handle(request, msg)
class RouterRebuildAction(tables.LinkAction):
name = "rebuild"
verbose_name = _("Rebuild Router")
classes = ("ajax-modal",)
def get_link_url(self, datum=None):
return reverse("horizon:admin:astaratenants:rebuild",
kwargs={'tenant_id': datum.tenant_id,
'router_id': datum.id})
class TenantRouterTable(tables.DataTable):
name = tables.Column("name", verbose_name=_("Name"),
link="horizon:admin:routers:detail")
status = tables.Column("status", verbose_name=_("Status"))
latest = tables.Column('latest', verbose_name=_("Latest"))
image_name = tables.Column('image_name', verbose_name=_("Image Name"))
last_fetch = tables.Column('last_fetch', verbose_name=_("Last Fetch"))
booted = tables.Column('booted', verbose_name=_("Booted"))
class Meta:
name = "routers"
verbose_name = _("Routers")
table_actions = (RouterManageAction, RouterDebugAction, )
status_columns = ('status',)
row_actions = (RouterRebuildAction, RouterUpdateAction,
RouterManageAction, RouterDebugAction, )

View File

@ -1,27 +0,0 @@
{% extends "horizon/common/_modal_form.html" %}
{% load i18n %}
{% load url from future %}
{% block form_id %}rebuild_astaratenants_form{% endblock %}
{% block form_action %}{% url 'horizon:admin:astaratenants:rebuild' router_id=router_id tenant_id=tenant_id %}{% endblock %}
{% block modal_id %}rebuild_astaratenants_modal{% endblock %}
{% block modal-header %}{% trans "Rebuild Router" %}{% endblock %}
{% block modal-body %}
<div class="left">
<fieldset>
{% include "horizon/common/_form_fields.html" %}
</fieldset>
</div>
<div class="right">
<h3>{% trans "Description" %}:</h3>
<p>{% trans "Choose image to rebuild router" %}</p>
</div>
{% endblock %}
{% block modal-footer %}
<input class="btn btn-primary" type="submit" value="{% trans "Rebuild Router" %}" />
<a href="{% url 'horizon:admin:astaratenants:index' %}" class="btn btn-default cancel">{% trans "Cancel" %}</a>
{% endblock %}

View File

@ -1,17 +0,0 @@
{% extends 'base.html' %}
{% load i18n %}
{% block title %}{% trans "Tenants" %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=_("Tenants") %}
{% endblock page_header %}
{% block main %}
<div class="row">
<div class="col-sm-12">
{{ table.render }}
</div>
</div>
{% endblock %}

View File

@ -1,11 +0,0 @@
{% extends 'base.html' %}
{% load i18n %}
{% block title %}{% trans "Rebuild Router" %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" with title=_("Rebuild Router") %}
{% endblock page_header %}
{% block main %}
{% include "admin/astaratenants/_rebuild.html" %}
{% endblock %}

View File

@ -1,17 +0,0 @@
{% extends 'base.html' %}
{% load i18n %}
{% block title %}{% trans "Routers" %}{% endblock %}
{% block page_header %}
{% include "horizon/common/_page_header.html" %}
{% endblock page_header %}
{% block main %}
<div class="row">
<div class="col-sm-12">
{{ table.render }}
</div>
</div>
{% endblock %}

View File

@ -1,29 +0,0 @@
# Copyright (c) 2015 Akanda, Inc. 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.
from django.conf.urls import patterns
from django.conf.urls import url
from astara_horizon.astara_openstack_dashboard.dashboards.admin.astaratenants \
import views
TENANT = r'^(?P<tenant_id>[^/]+)/%s$'
urlpatterns = patterns(
'astara_openstack_dashboard.dashboards.admin.astaratenants.views',
url(r'^$', views.TenantIndexView.as_view(), name='index'),
url(TENANT % '$', views.TenantRouterIndexView.as_view(), name='tenant'),
url(r'^(?P<tenant_id>[^/]+)/(?P<router_id>[^/]+)/rebuild$',
views.RebuildView.as_view(), name='rebuild'),
)

View File

@ -1,137 +0,0 @@
# Copyright (c) 2015 Akanda, Inc. 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.
from django.utils.translation import ugettext_lazy as _
from django.core.urlresolvers import reverse
from django.core.urlresolvers import reverse_lazy
from horizon import tables
from horizon import exceptions
from horizon import messages
from horizon import forms
from openstack_dashboard import api
from openstack_dashboard import policy
from astara_horizon.astara_openstack_dashboard.dashboards.admin.astaratenants \
import tables as tenant_tables
from astara_horizon.astara_openstack_dashboard.dashboards.admin.astararouters \
import forms as astararouters_forms
from astara_horizon.astara_openstack_dashboard.api.astara import AstaraClient
rc = AstaraClient()
class TenantIndexView(tables.DataTableView):
table_class = tenant_tables.TenantsTable
template_name = 'admin/astaratenants/index.html'
def has_more_data(self, table):
return self._more
def get_data(self):
tenants = []
marker = self.request.GET.get(
tenant_tables.TenantsTable._meta.pagination_param, None)
domain_context = self.request.session.get('domain_context', None)
if policy.check((("admin", "admin:list_projects"),), self.request):
try:
tenants, self._more = api.keystone.tenant_list(
self.request,
domain=domain_context,
paginate=True,
marker=marker)
except Exception:
self._more = False
exceptions.handle(self.request,
_("Unable to retrieve project list."))
elif policy.check((("admin", "identity:list_user_projects"),),
self.request):
try:
tenants, self._more = api.keystone.tenant_list(
self.request,
user=self.request.user.id,
paginate=True,
marker=marker,
admin=False)
except Exception:
self._more = False
exceptions.handle(self.request,
_("Unable to retrieve project information."))
else:
self._more = False
msg = \
_("Insufficient privilege level to view project information.")
messages.info(self.request, msg)
return tenants
class TenantRouterIndexView(tables.DataTableView):
table_class = tenant_tables.TenantRouterTable
template_name = 'admin/astaratenants/router-index.html'
def has_prev_data(self, table):
return getattr(self, "_prev", False)
def has_more_data(self, table):
return getattr(self, "_more", False)
def get_context_data(self, **kwargs):
context = super(TenantRouterIndexView, self).get_context_data(**kwargs)
context["tenant_id"] = self.kwargs['tenant_id']
tenant = api.keystone.tenant_get(self.request,
self.kwargs['tenant_id'],
admin=True)
context["title"] = "Routers of tenant \"%s\"" % tenant.name
return context
def get_data(self):
try:
routers, self._more = rc.get_routers(
self.request,
tenant_id=self.kwargs['tenant_id']
)
return routers
except Exception:
url = reverse('horizon:admin:astaratenants:index')
exceptions.handle(self.request,
_('Unable to retrieve routers\' details.'),
redirect=url)
class RebuildView(forms.ModalFormView):
form_class = astararouters_forms.RebuildForm
template_name = 'admin/astaratenants/rebuild.html'
success_url = reverse_lazy('horizon:admin:astaratenants:index')
def get_success_url(self):
return reverse("horizon:admin:astaratenants:tenant",
args=(self.kwargs['tenant_id'],))
def get_context_data(self, **kwargs):
self.router = api.neutron.router_get(self.request,
self.kwargs['router_id'])
context = super(RebuildView, self).get_context_data(**kwargs)
context["router_id"] = self.kwargs['router_id']
context["tenant_id"] = self.kwargs['tenant_id']
context["router_name"] = self.router['name']
return context
def get_initial(self):
return {
'router_id': self.kwargs['router_id'],
'tenant_id': self.kwargs['tenant_id'],
'router_name': self.get_context_data()['router_name']
}

View File

@ -1,24 +0,0 @@
# Copyright (c) 2015 Akanda, Inc. 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.
from openstack_dashboard.dashboards.admin.networks import views
from openstack_dashboard.dashboards.admin.networks.ports \
import tables as ports_tables
from openstack_dashboard.dashboards.admin.networks.subnets \
import tables as subnets_tables
# override network tables to delete dhcp agent table
views.DetailView.table_classes = (subnets_tables.SubnetsTable,
ports_tables.PortsTable)

View File

@ -1,20 +0,0 @@
# Copyright (c) 2015 Akanda, Inc. 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.
# The name of the panel group to be added to HORIZON_CONFIG. Required.
PANEL_GROUP = 'astara'
# The display name of the PANEL_GROUP. Required.
PANEL_GROUP_NAME = 'Astara'
# The name of the dashboard the PANEL_GROUP associated with. Required.
PANEL_GROUP_DASHBOARD = 'admin'

View File

@ -1,24 +0,0 @@
# Copyright (c) 2015 Akanda, Inc. 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.
# The name of the panel to be added to HORIZON_CONFIG. Required.
PANEL = 'astararouters'
# The name of the dashboard the PANEL associated with. Required.
PANEL_DASHBOARD = 'admin'
# The name of the panel group the PANEL is associated with.
PANEL_GROUP = 'astara'
# Python panel class of the PANEL to be added.
ADD_PANEL = \
'astara_horizon.astara_openstack_dashboard.dashboards.admin.astararouters.panel.AstaraRouters'

View File

@ -1,26 +0,0 @@
# Copyright (c) 2015 Akanda, Inc. 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.
# The name of the panel to be added to HORIZON_CONFIG. Required.
PANEL = 'astaratenants'
# The name of the dashboard the PANEL associated with. Required.
PANEL_DASHBOARD = 'admin'
# The name of the panel group the PANEL is associated with.
PANEL_GROUP = 'astara'
# Python panel class of the PANEL to be added.
ADD_PANEL = (
'astara_horizon.astara_openstack_dashboard.dashboards.admin.astaratenants.'
'panel.AstaraTenants')

View File

@ -1,41 +0,0 @@
[metadata]
name = astara-horizon
summary = Astara plugin for Horizon
description-file =
README.md
author = OpenStack
author-email = openstack-dev@lists.openstack.org
home-page = http://github.com/openstack/astara-horizon
classifier =
Environment :: OpenStack
Intended Audience :: Developers
Intended Audience :: Information Technology
Intended Audience :: System Administrators
License :: OSI Approved :: Apache Software License
Operating System :: POSIX :: Linux
Programming Language :: Python
Programming Language :: Python :: 2
Programming Language :: Python :: 2.7
[files]
packages =
astara_horizon
astara_horizon.astara_openstack_dashboard
namespace_packages =
astara_horizon
[global]
setup-hooks =
pbr.hooks.setup_hook
[build_sphinx]
all_files = 1
build-dir = doc/build
source-dir = doc/source
[nosetests]
where = test
verbosity = 2
detailed-errors = 1
cover-package = astara_horizon

View File

@ -1,29 +0,0 @@
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
#
# 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.
# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT
import setuptools
# In python < 2.7.4, a lazy loading of package `pbr` will break
# setuptools if some other modules registered functions in `atexit`.
# solution from: http://bugs.python.org/issue15881#msg170215
try:
import multiprocessing # noqa
except ImportError:
pass
setuptools.setup(
setup_requires=['pbr>=1.8'],
pbr=True)

View File

@ -1,15 +0,0 @@
# The order of packages is significant, because pip processes them in the order
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
unittest2 # BSD
nose # LGPL
coverage>=3.6 # Apache-2.0
mock>=2.0 # BSD
pep8==1.5.7 # MIT
eventlet!=0.18.3,>=0.18.2 # MIT
iso8601>=0.1.11 # MIT
python-novaclient!=2.33.0,>=2.29.0 # Apache-2.0
WebOb>=1.2.3 # MIT
mox>=0.5.3 # Apache-2.0
testtools>=1.4.0 # MIT
fixtures>=3.0.0 # Apache-2.0/BSD

View File

@ -1 +0,0 @@
./README.md

33
tox.ini
View File

@ -1,33 +0,0 @@
[tox]
envlist = py27,pep8
[testenv]
distribute = False
setenv = VIRTUAL_ENV={envdir}
deps = -r{toxinidir}/test-requirements.txt
commands = nosetests --with-coverage {posargs}
sitepackages = False
[tox:jenkins]
[testenv:style]
deps = flake8
setuptools_git>=0.4
commands = flake8 astara_horizon setup.py
[testenv:pep8]
deps = {[testenv:style]deps}
commands = {[testenv:style]commands}
[testenv:doc]
deps = Sphinx
commands = sphinx-build doc/source doc/build
[testenv:cover]
setenv = NOSE_WITH_COVERAGE=1
[testenv:venv]
commands = {posargs}
[flake8]
ignore = E133,E226,E241,E242,E731