Add autodiscovery form
Change-Id: I00b5685ddae7b45d564ff8f756beee3a1fca94ef
This commit is contained in:
parent
585df2b1a3
commit
986fa74186
@ -70,10 +70,10 @@ class IronicNode(base.APIResourceWrapper):
|
|||||||
self._request = request
|
self._request = request
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create(cls, request, ipmi_address, cpu_arch, cpus, memory_mb,
|
def create(cls, request, ipmi_address=None, cpu_arch=None, cpus=None,
|
||||||
local_gb, mac_addresses, ipmi_username=None, ipmi_password=None,
|
memory_mb=None, local_gb=None, mac_addresses=[],
|
||||||
ssh_address=None, ssh_username=None, ssh_key_contents=None,
|
ipmi_username=None, ipmi_password=None, ssh_address=None,
|
||||||
driver=None):
|
ssh_username=None, ssh_key_contents=None, driver=None):
|
||||||
"""Create a Node in Ironic
|
"""Create a Node in Ironic
|
||||||
"""
|
"""
|
||||||
if driver == 'pxe_ssh':
|
if driver == 'pxe_ssh':
|
||||||
@ -447,10 +447,10 @@ class Node(base.APIResourceWrapper):
|
|||||||
self._instance = kwargs['instance']
|
self._instance = kwargs['instance']
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create(cls, request, ipmi_address, cpu_arch, cpus, memory_mb,
|
def create(cls, request, ipmi_address=None, cpu_arch=None, cpus=None,
|
||||||
local_gb, mac_addresses, ipmi_username=None, ipmi_password=None,
|
memory_mb=None, local_gb=None, mac_addresses=[],
|
||||||
driver=None, ssh_address=None, ssh_username=None,
|
ipmi_username=None, ipmi_password=None, ssh_address=None,
|
||||||
ssh_key_contents=None):
|
ssh_username=None, ssh_key_contents=None, driver=None):
|
||||||
return cls(NodeClient(request).node_class.create(
|
return cls(NodeClient(request).node_class.create(
|
||||||
request, ipmi_address, cpu_arch, cpus, memory_mb, local_gb,
|
request, ipmi_address, cpu_arch, cpus, memory_mb, local_gb,
|
||||||
mac_addresses, ipmi_username=ipmi_username,
|
mac_addresses, ipmi_username=ipmi_username,
|
||||||
|
@ -145,8 +145,8 @@ class NodeForm(django.forms.Form):
|
|||||||
|
|
||||||
def get_name(self):
|
def get_name(self):
|
||||||
try:
|
try:
|
||||||
# FIXME(lsmola) show somethign meaningful here
|
name = (self.fields['ipmi_address'].value() or
|
||||||
name = self.fields['ipmi_address'].value()
|
self.fields['ssh_address'].value())
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
# when the field is not bound
|
# when the field is not bound
|
||||||
name = _("Undefined node")
|
name = _("Undefined node")
|
||||||
@ -208,3 +208,70 @@ class BaseNodeFormset(django.forms.formsets.BaseFormSet):
|
|||||||
|
|
||||||
NodeFormset = django.forms.formsets.formset_factory(NodeForm, extra=1,
|
NodeFormset = django.forms.formsets.formset_factory(NodeForm, extra=1,
|
||||||
formset=BaseNodeFormset)
|
formset=BaseNodeFormset)
|
||||||
|
|
||||||
|
|
||||||
|
class AutoDiscoverNodeForm(django.forms.Form):
|
||||||
|
id = django.forms.IntegerField(
|
||||||
|
label="",
|
||||||
|
required=False,
|
||||||
|
widget=django.forms.HiddenInput(),
|
||||||
|
)
|
||||||
|
ssh_address = django.forms.IPAddressField(
|
||||||
|
label=_("SSH Address"),
|
||||||
|
required=False,
|
||||||
|
widget=django.forms.TextInput,
|
||||||
|
)
|
||||||
|
ssh_username = django.forms.CharField(
|
||||||
|
label=_("SSH User"),
|
||||||
|
required=False,
|
||||||
|
widget=django.forms.TextInput,
|
||||||
|
)
|
||||||
|
ssh_key_contents = django.forms.CharField(
|
||||||
|
label=_("SSH Key Contents"),
|
||||||
|
required=False,
|
||||||
|
widget=django.forms.Textarea(attrs={
|
||||||
|
'rows': 2,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_name(self):
|
||||||
|
try:
|
||||||
|
name = self.fields['ssh_address'].value()
|
||||||
|
except AttributeError:
|
||||||
|
# when the field is not bound
|
||||||
|
name = _("Undefined node")
|
||||||
|
return name
|
||||||
|
|
||||||
|
|
||||||
|
class BaseAutoDiscoverNodeFormset(BaseNodeFormset):
|
||||||
|
def handle(self, request, data):
|
||||||
|
success = True
|
||||||
|
for form in self:
|
||||||
|
data = form.cleaned_data
|
||||||
|
try:
|
||||||
|
node = api.node.Node.create(
|
||||||
|
request,
|
||||||
|
ssh_address=data['ssh_address'],
|
||||||
|
ssh_username=data.get('ssh_username'),
|
||||||
|
ssh_key_contents=data.get('ssh_key_contents'),
|
||||||
|
driver='pxe_ssh'
|
||||||
|
)
|
||||||
|
api.node.Node.set_maintenance(request,
|
||||||
|
node.uuid,
|
||||||
|
True)
|
||||||
|
#TODO(tzumainn): now we need to boot the node
|
||||||
|
except Exception:
|
||||||
|
success = False
|
||||||
|
exceptions.handle(request, _('Unable to register node.'))
|
||||||
|
# TODO(rdopieralski) Somehow find out if any port creation
|
||||||
|
# failed and remove the mac addresses that succeeded from
|
||||||
|
# the form.
|
||||||
|
else:
|
||||||
|
# TODO(rdopieralski) Remove successful nodes from formset.
|
||||||
|
pass
|
||||||
|
return success
|
||||||
|
|
||||||
|
|
||||||
|
AutoDiscoverNodeFormset = django.forms.formsets.formset_factory(
|
||||||
|
AutoDiscoverNodeForm, extra=1,
|
||||||
|
formset=BaseAutoDiscoverNodeFormset)
|
||||||
|
@ -29,9 +29,9 @@ class OverviewTab(tabs.Tab):
|
|||||||
|
|
||||||
def get_context_data(self, request):
|
def get_context_data(self, request):
|
||||||
nodes = api.node.Node.list(request)
|
nodes = api.node.Node.list(request)
|
||||||
cpus = sum(int(node.cpus) for node in nodes)
|
cpus = sum(int(node.cpus or 0) for node in nodes)
|
||||||
memory_mb = sum(int(node.memory_mb) for node in nodes)
|
memory_mb = sum(int(node.memory_mb or 0) for node in nodes)
|
||||||
local_gb = sum(int(node.local_gb) for node in nodes)
|
local_gb = sum(int(node.local_gb or 0) for node in nodes)
|
||||||
deployed_nodes = api.node.Node.list(request, associated=True)
|
deployed_nodes = api.node.Node.list(request, associated=True)
|
||||||
free_nodes = api.node.Node.list(request, associated=False)
|
free_nodes = api.node.Node.list(request, associated=False)
|
||||||
deployed_nodes_error = api.node.filter_nodes(
|
deployed_nodes_error = api.node.filter_nodes(
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
{% extends "horizon/common/_modal_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% load url from future %}
|
||||||
|
|
||||||
|
{% block form_id %}auto_discover_nodes_form{% endblock %}
|
||||||
|
{% block form_action %}{% url 'horizon:infrastructure:nodes:auto-discover' %}{% endblock %}
|
||||||
|
{% block modal_id %}register_nodes_modal{% endblock %}
|
||||||
|
{% block modal-header %}{% trans "Auto-Discover Nodes" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-body %}
|
||||||
|
{% include "formset_table/menu_formset.html" with formset=form form_template="infrastructure/nodes/_auto_discover_nodes_formset_form.html" %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-footer %}
|
||||||
|
<input class="btn btn-primary pull-right" type="submit"
|
||||||
|
value="{% trans "Auto-Discover Nodes" %}" />
|
||||||
|
<a href="{% url 'horizon:infrastructure:nodes:index' %}"
|
||||||
|
class="btn secondary cancel close">{% trans "Cancel" %}</a>
|
||||||
|
{% endblock %}
|
||||||
|
|
@ -0,0 +1,26 @@
|
|||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
<div class="well tab-pane{% if active %} active{% endif %}"
|
||||||
|
id="tab-{{ form.prefix }}">
|
||||||
|
<div class="form form-inline"><fieldset>
|
||||||
|
<div class="row">
|
||||||
|
<h5>{% trans 'Power Management' %}</h5>
|
||||||
|
{% include 'infrastructure/nodes/_nodes_formset_field.html' with field=form.ssh_address %}
|
||||||
|
{% include 'infrastructure/nodes/_nodes_formset_field.html' with field=form.ssh_username %}
|
||||||
|
{% include 'infrastructure/nodes/_nodes_formset_field.html' with field=form.ssh_key_contents %}
|
||||||
|
</div>
|
||||||
|
</fieldset></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
(window.$ || window.addHorizonLoadEvent)(function () {
|
||||||
|
var form_prefix = '{{ form.prefix|escapejs }}';
|
||||||
|
var $form = $('#tab-' + form_prefix);
|
||||||
|
var $nav_link = $('a[href="#' + $form.attr('id') + '"]');
|
||||||
|
var undefined_name = '{{ form.get_name|escapejs }}';
|
||||||
|
|
||||||
|
$form.find('input[name$="-ssh_address"]').change(function () {
|
||||||
|
$nav_link.html($(this).val() || undefined_name);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
@ -0,0 +1,11 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block title %}{% trans "Auto-Discover Nodes" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_header %}
|
||||||
|
{% include "horizon/common/_page_header.html" with title=_("Auto-Discover Nodes") %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
{% include "infrastructure/nodes/_auto_discover.html" %}
|
||||||
|
{% endblock %}
|
@ -15,6 +15,12 @@
|
|||||||
<span class="glyphicon glyphicon-plus"></span>
|
<span class="glyphicon glyphicon-plus"></span>
|
||||||
{% trans 'Register Nodes' %}
|
{% trans 'Register Nodes' %}
|
||||||
</a>
|
</a>
|
||||||
|
{% if ironic_enabled %}
|
||||||
|
<a href="{% url 'horizon:infrastructure:nodes:auto-discover' %}" class="btn btn-primary ajax-modal">
|
||||||
|
<span class="glyphicon glyphicon-plus"></span>
|
||||||
|
{% trans 'Auto-Discover Nodes' %}
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{{ tab_group.render }}
|
{{ tab_group.render }}
|
||||||
</div>
|
</div>
|
||||||
|
@ -22,6 +22,8 @@ urlpatterns = urls.patterns(
|
|||||||
urls.url(r'^$', views.IndexView.as_view(), name='index'),
|
urls.url(r'^$', views.IndexView.as_view(), name='index'),
|
||||||
urls.url(r'^register/$', views.RegisterView.as_view(),
|
urls.url(r'^register/$', views.RegisterView.as_view(),
|
||||||
name='register'),
|
name='register'),
|
||||||
|
urls.url(r'^auto-discover/$', views.AutoDiscoverView.as_view(),
|
||||||
|
name='auto-discover'),
|
||||||
urls.url(r'^(?P<node_uuid>[^/]+)/$', views.DetailView.as_view(),
|
urls.url(r'^(?P<node_uuid>[^/]+)/$', views.DetailView.as_view(),
|
||||||
name='detail'),
|
name='detail'),
|
||||||
urls.url(r'^(?P<node_uuid>[^/]+)/performance/$',
|
urls.url(r'^(?P<node_uuid>[^/]+)/performance/$',
|
||||||
|
@ -35,6 +35,12 @@ class IndexView(horizon_tabs.TabbedTableView):
|
|||||||
tab_group_class = tabs.NodeTabs
|
tab_group_class = tabs.NodeTabs
|
||||||
template_name = 'infrastructure/nodes/index.html'
|
template_name = 'infrastructure/nodes/index.html'
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super(IndexView, self).get_context_data(**kwargs)
|
||||||
|
context['ironic_enabled'] = api.node.NodeClient.ironic_enabled(
|
||||||
|
self.request)
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
class RegisterView(horizon_forms.ModalFormView):
|
class RegisterView(horizon_forms.ModalFormView):
|
||||||
form_class = forms.NodeFormset
|
form_class = forms.NodeFormset
|
||||||
@ -52,6 +58,19 @@ class RegisterView(horizon_forms.ModalFormView):
|
|||||||
prefix=self.form_prefix)
|
prefix=self.form_prefix)
|
||||||
|
|
||||||
|
|
||||||
|
class AutoDiscoverView(horizon_forms.ModalFormView):
|
||||||
|
form_class = forms.AutoDiscoverNodeFormset
|
||||||
|
form_prefix = 'auto_discover_nodes'
|
||||||
|
template_name = 'infrastructure/nodes/auto_discover.html'
|
||||||
|
success_url = reverse_lazy(
|
||||||
|
'horizon:infrastructure:nodes:index')
|
||||||
|
|
||||||
|
def get_form(self, form_class):
|
||||||
|
return form_class(self.request.POST or None,
|
||||||
|
initial=[],
|
||||||
|
prefix=self.form_prefix)
|
||||||
|
|
||||||
|
|
||||||
class DetailView(horizon_views.APIView):
|
class DetailView(horizon_views.APIView):
|
||||||
template_name = 'infrastructure/nodes/details.html'
|
template_name = 'infrastructure/nodes/details.html'
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user