Merge "Enable host aggregate metadata update"
This commit is contained in:
commit
57e332b8ef
|
@ -795,6 +795,10 @@ def aggregate_update(request, aggregate_id, values):
|
|||
return novaclient(request).aggregates.update(aggregate_id, values)
|
||||
|
||||
|
||||
def aggregate_set_metadata(request, aggregate_id, metadata):
|
||||
return novaclient(request).aggregates.set_metadata(aggregate_id, metadata)
|
||||
|
||||
|
||||
def host_list(request):
|
||||
return novaclient(request).hosts.list()
|
||||
|
||||
|
|
|
@ -17,5 +17,9 @@ AGGREGATES_CREATE_URL = 'horizon:admin:aggregates:create'
|
|||
AGGREGATES_CREATE_VIEW_TEMPLATE = 'admin/aggregates/create.html'
|
||||
AGGREGATES_MANAGE_HOSTS_URL = 'horizon:admin:aggregates:manage_hosts'
|
||||
AGGREGATES_MANAGE_HOSTS_TEMPLATE = 'admin/aggregates/manage_hosts.html'
|
||||
AGGREGATES_UPDATE_METADATA_URL = 'horizon:admin:aggregates:update_metadata'
|
||||
AGGREGATES_UPDATE_METADATA_TEMPLATE = 'admin/aggregates/update_metadata.html'
|
||||
AGGREGATES_UPDATE_METADATA_SUBTEMPLATE = \
|
||||
'admin/aggregates/_update_metadata.html'
|
||||
AGGREGATES_UPDATE_URL = 'horizon:admin:aggregates:update'
|
||||
AGGREGATES_UPDATE_VIEW_TEMPLATE = 'admin/aggregates/update.html'
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import json
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from horizon import exceptions
|
||||
|
@ -47,3 +49,32 @@ class UpdateAggregateForm(forms.SelfHandlingForm):
|
|||
exceptions.handle(request,
|
||||
_('Unable to update the aggregate.'))
|
||||
return True
|
||||
|
||||
|
||||
class UpdateMetadataForm(forms.SelfHandlingForm):
|
||||
|
||||
def handle(self, request, data):
|
||||
id = self.initial['id']
|
||||
old_metadata = self.initial['metadata']
|
||||
|
||||
try:
|
||||
new_metadata = json.loads(self.data['metadata'])
|
||||
|
||||
metadata = dict(
|
||||
(item['key'], str(item['value']))
|
||||
for item in new_metadata
|
||||
)
|
||||
|
||||
for key in old_metadata:
|
||||
if key not in metadata:
|
||||
metadata[key] = None
|
||||
|
||||
api.nova.aggregate_set_metadata(request, id, metadata)
|
||||
message = _('Metadata successfully updated.')
|
||||
messages.success(request, message)
|
||||
except Exception:
|
||||
msg = _('Unable to update the aggregate metadata.')
|
||||
exceptions.handle(request, msg)
|
||||
|
||||
return False
|
||||
return True
|
||||
|
|
|
@ -45,6 +45,14 @@ class ManageHostsAction(tables.LinkAction):
|
|||
icon = "plus"
|
||||
|
||||
|
||||
class UpdateMetadataAction(tables.LinkAction):
|
||||
name = "update-metadata"
|
||||
verbose_name = _("Update Metadata")
|
||||
url = constants.AGGREGATES_UPDATE_METADATA_URL
|
||||
classes = ("ajax-modal",)
|
||||
icon = "pencil"
|
||||
|
||||
|
||||
class UpdateAggregateAction(tables.LinkAction):
|
||||
name = "update"
|
||||
verbose_name = _("Edit Host Aggregate")
|
||||
|
@ -123,6 +131,7 @@ class HostAggregatesTable(tables.DataTable):
|
|||
DeleteAggregateAction)
|
||||
row_actions = (UpdateAggregateAction,
|
||||
ManageHostsAction,
|
||||
UpdateMetadataAction,
|
||||
DeleteAggregateAction)
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
{% extends 'horizon/common/_modal_form_update_metadata.html' %}
|
||||
{% load i18n %}
|
||||
{% load url from future %}
|
||||
{% block title %}{% trans "Update Aggregate Metadata" %}{% endblock %}
|
||||
|
||||
{% block page_header %}
|
||||
{% include "horizon/common/_page_header.html" with title=_("Update Aggregate Metadata") %}
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block form_action %}{% url 'horizon:admin:aggregates:update_metadata' id %}{% endblock %}
|
||||
{% block modal-header %}{% trans "Update Metadata" %}{% endblock %}
|
|
@ -0,0 +1,11 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Update Aggregate Metadata" %}{% endblock %}
|
||||
|
||||
{% block page_header %}
|
||||
{% include "horizon/common/_page_header.html" with title=_("Update Aggregate Metadata") %}
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'admin/aggregates/_update_metadata.html' %}
|
||||
{% endblock %}
|
|
@ -10,6 +10,7 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import json
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django import http
|
||||
|
@ -433,3 +434,82 @@ class ManageHostsTests(test.BaseAdminViewTests):
|
|||
form_data,
|
||||
addAggregate=False,
|
||||
cleanAggregates=True)
|
||||
|
||||
|
||||
class HostAggregateMetadataTests(test.BaseAdminViewTests):
|
||||
|
||||
@test.create_stubs({api.nova: ('aggregate_get',),
|
||||
api.glance: ('metadefs_namespace_list',
|
||||
'metadefs_namespace_get')})
|
||||
def test_host_aggregate_metadata_get(self):
|
||||
aggregate = self.aggregates.first()
|
||||
api.nova.aggregate_get(
|
||||
IsA(http.HttpRequest),
|
||||
str(aggregate.id)
|
||||
).AndReturn(aggregate)
|
||||
|
||||
namespaces = self.metadata_defs.list()
|
||||
|
||||
api.glance.metadefs_namespace_list(
|
||||
IsA(http.HttpRequest),
|
||||
filters={'resource_types': ['OS::Nova::Aggregate']}
|
||||
).AndReturn((namespaces, False, False))
|
||||
|
||||
for namespace in namespaces:
|
||||
api.glance.metadefs_namespace_get(
|
||||
IsA(http.HttpRequest),
|
||||
namespace.namespace,
|
||||
'OS::Nova::Aggregate'
|
||||
).AndReturn(namespace)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
res = self.client.get(
|
||||
reverse(constants.AGGREGATES_UPDATE_METADATA_URL,
|
||||
args=[aggregate.id]))
|
||||
|
||||
self.assertEqual(res.status_code, 200)
|
||||
self.assertTemplateUsed(
|
||||
res,
|
||||
constants.AGGREGATES_UPDATE_METADATA_TEMPLATE
|
||||
)
|
||||
self.assertTemplateUsed(
|
||||
res,
|
||||
constants.AGGREGATES_UPDATE_METADATA_SUBTEMPLATE
|
||||
)
|
||||
self.assertContains(res, 'namespace_1')
|
||||
self.assertContains(res, 'namespace_2')
|
||||
self.assertContains(res, 'namespace_3')
|
||||
self.assertContains(res, 'namespace_4')
|
||||
|
||||
@test.create_stubs({api.nova: ('aggregate_get', 'aggregate_set_metadata')})
|
||||
def test_host_aggregate_metadata_update(self):
|
||||
aggregate = self.aggregates.first()
|
||||
aggregate.metadata = {'key': 'test_key', 'value': 'test_value'}
|
||||
|
||||
api.nova.aggregate_get(
|
||||
IsA(http.HttpRequest),
|
||||
str(aggregate.id)
|
||||
).AndReturn(aggregate)
|
||||
|
||||
api.nova.aggregate_set_metadata(
|
||||
IsA(http.HttpRequest),
|
||||
str(aggregate.id),
|
||||
{'value': None, 'key': None, 'test_key': 'test_value'}
|
||||
).AndReturn(None)
|
||||
|
||||
self.mox.ReplayAll()
|
||||
|
||||
form_data = {"metadata": json.dumps([aggregate.metadata])}
|
||||
|
||||
res = self.client.post(
|
||||
reverse(constants.AGGREGATES_UPDATE_METADATA_URL,
|
||||
args=(aggregate.id,)), form_data)
|
||||
|
||||
self.assertEqual(res.status_code, 302)
|
||||
self.assertNoFormErrors(res)
|
||||
self.assertMessageCount(success=1)
|
||||
self.assertRedirectsNoFollow(
|
||||
res,
|
||||
reverse(constants.AGGREGATES_INDEX_URL)
|
||||
)
|
||||
|
|
|
@ -24,6 +24,8 @@ urlpatterns = patterns('openstack_dashboard.dashboards.admin.aggregates.views',
|
|||
views.CreateView.as_view(), name='create'),
|
||||
url(r'^(?P<id>[^/]+)/update/$',
|
||||
views.UpdateView.as_view(), name='update'),
|
||||
url(r'^(?P<id>[^/]+)/update_metadata/$',
|
||||
views.UpdateMetadataView.as_view(), name='update_metadata'),
|
||||
url(r'^(?P<id>[^/]+)/manage_hosts/$',
|
||||
views.ManageHostsView.as_view(), name='manage_hosts'),
|
||||
)
|
||||
|
|
|
@ -10,12 +10,15 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import json
|
||||
|
||||
from django.core.urlresolvers import reverse_lazy
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from horizon import exceptions
|
||||
from horizon import forms
|
||||
from horizon import tables
|
||||
from horizon.utils import memoized
|
||||
from horizon import workflows
|
||||
|
||||
from openstack_dashboard import api
|
||||
|
@ -94,6 +97,59 @@ class UpdateView(forms.ModalFormView):
|
|||
return self._object
|
||||
|
||||
|
||||
class UpdateMetadataView(forms.ModalFormView):
|
||||
template_name = constants.AGGREGATES_UPDATE_METADATA_TEMPLATE
|
||||
form_class = aggregate_forms.UpdateMetadataForm
|
||||
success_url = reverse_lazy(constants.AGGREGATES_INDEX_URL)
|
||||
|
||||
def get_initial(self):
|
||||
aggregate = self.get_object()
|
||||
return {'id': self.kwargs["id"], 'metadata': aggregate.metadata}
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(UpdateMetadataView, self).get_context_data(**kwargs)
|
||||
|
||||
aggregate = self.get_object()
|
||||
try:
|
||||
context['existing_metadata'] = json.dumps(aggregate.metadata)
|
||||
except Exception:
|
||||
msg = _('Unable to retrieve aggregate metadata.')
|
||||
exceptions.handle(self.request, msg)
|
||||
|
||||
resource_type = 'OS::Nova::Aggregate'
|
||||
metadata = {}
|
||||
try:
|
||||
# metadefs_namespace_list() returns a tuple with list as 1st elem
|
||||
metadata["namespaces"] = [
|
||||
api.glance.metadefs_namespace_get(self.request, x.namespace,
|
||||
resource_type)
|
||||
for x in api.glance.metadefs_namespace_list(
|
||||
self.request,
|
||||
filters={"resource_types": [resource_type]}
|
||||
)[0]
|
||||
]
|
||||
|
||||
context['available_metadata'] = json.dumps(metadata)
|
||||
except Exception:
|
||||
msg = _('Unable to retrieve available metadata for aggregate.')
|
||||
exceptions.handle(self.request, msg)
|
||||
|
||||
context['id'] = self.kwargs['id']
|
||||
return context
|
||||
|
||||
@memoized.memoized_method
|
||||
def get_object(self):
|
||||
aggregate_id = self.kwargs['id']
|
||||
try:
|
||||
aggregate = api.nova.aggregate_get(self.request, aggregate_id)
|
||||
except Exception:
|
||||
msg = _('Unable to retrieve the aggregate to be '
|
||||
'updated.')
|
||||
exceptions.handle(self.request, msg)
|
||||
else:
|
||||
return aggregate
|
||||
|
||||
|
||||
class ManageHostsView(workflows.WorkflowView):
|
||||
template_name = constants.AGGREGATES_MANAGE_HOSTS_TEMPLATE
|
||||
workflow_class = aggregate_workflows.ManageAggregateHostsWorkflow
|
||||
|
|
Loading…
Reference in New Issue