Updated design. Removed extra code.

This commit is contained in:
Timur Nurlygayanov 2013-02-16 03:10:02 -08:00
parent 45a2d84d72
commit 505c3da3a4
8 changed files with 148 additions and 189 deletions

View File

@ -1,6 +1,7 @@
# TO DO: # TO DO:
# 1. Remove extra code # 1. Add new functional for services and data centers
# # 2. Fix issue with list of services: services table shoudl show services for
# specific data center
This file is described how to install new tab on horizon dashboard. This file is described how to install new tab on horizon dashboard.
We should do the following: We should do the following:

View File

@ -33,20 +33,20 @@ from horizon import messages
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
class UpdateInstance(forms.SelfHandlingForm): class UpdateWinDC(forms.SelfHandlingForm):
tenant_id = forms.CharField(widget=forms.HiddenInput) tenant_id = forms.CharField(widget=forms.HiddenInput)
instance = forms.CharField(widget=forms.HiddenInput) data_center = forms.CharField(widget=forms.HiddenInput)
name = forms.CharField(required=True) name = forms.CharField(required=True)
def handle(self, request, data): def handle(self, request, data):
try: try:
server = api.nova.server_update(request, data['instance'], server = api.nova.server_update(request, data['data_center'],
data['name']) data['name'])
messages.success(request, messages.success(request,
_('Instance "%s" updated.') % data['name']) _('Data Center "%s" updated.') % data['name'])
return server return server
except: except:
redirect = reverse("horizon:project:windc:index") redirect = reverse("horizon:project:windc:index")
exceptions.handle(request, exceptions.handle(request,
_('Unable to update instance.'), _('Unable to update data center.'),
redirect=redirect) redirect=redirect)

View File

@ -22,7 +22,7 @@ from openstack_dashboard.dashboards.project import dashboard
class WinDC(horizon.Panel): class WinDC(horizon.Panel):
name = _("Windows Services") name = _("Windows Data Centers")
slug = 'windc' slug = 'windc'

View File

@ -14,6 +14,10 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# TO DO: clear extra modules
import logging import logging
from django import shortcuts from django import shortcuts
@ -37,98 +41,32 @@ from openstack_dashboard.dashboards.project.access_and_security \
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
ACTIVE_STATES = ("ACTIVE",)
POWER_STATES = {
0: "NO STATE",
1: "RUNNING",
2: "SHUTDOWN",
3: "FAILED",
4: "BUILDING",
}
PAUSE = 0
UNPAUSE = 1
SUSPEND = 0
RESUME = 1
def is_deleting(instance):
task_state = getattr(instance, "OS-EXT-STS:task_state", None)
if not task_state:
return False
return task_state.lower() == "deleting"
class RebootService(tables.BatchAction):
name = "reboot"
action_present = _("Reboot")
action_past = _("Rebooted")
data_type_singular = _("Service")
data_type_plural = _("Services")
classes = ('btn-danger', 'btn-reboot')
def allowed(self, request, instance=None):
return ((instance.status in ACTIVE_STATES
or instance.status == 'SHUTOFF')
and not is_deleting(instance))
def action(self, request, obj_id):
api.nova.server_reboot(request, obj_id)
class CreateService(tables.LinkAction): class CreateService(tables.LinkAction):
name = "CreateService" name = "CreateService"
verbose_name = _("Create Windows Service") verbose_name = _("Create Service")
url = "horizon:project:windc:create" url = "horizon:project:windc:create"
classes = ("btn-launch", "ajax-modal") classes = ("btn-launch", "ajax-modal")
def allowed(self, request, datum): def allowed(self, request, datum):
try:
limits = api.nova.tenant_absolute_limits(request, reserved=True)
instances_available = limits['maxTotalInstances'] \
- limits['totalInstancesUsed']
cores_available = limits['maxTotalCores'] \
- limits['totalCoresUsed']
ram_available = limits['maxTotalRAMSize'] - limits['totalRAMUsed']
if instances_available <= 0 or cores_available <= 0 \
or ram_available <= 0:
if "disabled" not in self.classes:
self.classes = [c for c in self.classes] + ['disabled']
self.verbose_name = string_concat(self.verbose_name, ' ',
_("(Quota exceeded)"))
else:
self.verbose_name = _("Create Windows Service")
classes = [c for c in self.classes if c != "disabled"]
self.classes = classes
except:
LOG.exception("Failed to retrieve quota information")
# If we can't get the quota information, leave it to the
# API to check when launching
return True # The action should always be displayed
class DeleteService(tables.BatchAction):
name = "DeleteService"
action_present = _("DeleteService")
action_past = _("Scheduled termination of")
data_type_singular = _("Service")
data_type_plural = _("Services")
classes = ('btn-danger', 'btn-terminate')
def allowed(self, request, instance=None):
if instance:
# FIXME(gabriel): This is true in Essex, but in FOLSOM an instance
# can be terminated in any state. We should improve this error
# handling when LP bug 1037241 is implemented.
return instance.status not in ("PAUSED", "SUSPENDED")
return True return True
def action(self, request, obj_id): def action(self, request, obj_id):
api.nova.server_delete(request, obj_id) # FIX ME
api.windc.datacenter.create_service(request, obj_id)
class CreateDataCenter(tables.LinkAction):
name = "CreateDataCenter"
verbose_name = _("Create Windows Data Center")
url = "horizon:project:windc:create_dc"
classes = ("btn-launch", "ajax-modal")
def allowed(self, request, datum):
return True
def action(self, request, obj_id):
# FIX ME
api.windc.datacenter.create(request, obj_id)
class EditService(tables.LinkAction): class EditService(tables.LinkAction):
@ -138,7 +76,15 @@ class EditService(tables.LinkAction):
classes = ("ajax-modal", "btn-edit") classes = ("ajax-modal", "btn-edit")
def allowed(self, request, instance): def allowed(self, request, instance):
return not is_deleting(instance) return True
class ShowDataCenterServices(tables.LinkAction):
name = "edit"
verbose_name = _("Services")
url = "horizon:project:windc:services"
def allowed(self, request, instance):
return True
class UpdateRow(tables.Row): class UpdateRow(tables.Row):
ajax = True ajax = True
@ -150,45 +96,26 @@ class UpdateRow(tables.Row):
return instance return instance
def get_ips(instance): class WinDCTable(tables.DataTable):
template_name = 'project/windc/_instance_ips.html' TASK_STATUS_CHOICES = (
context = {"instance": instance} (None, True),
return template.loader.render_to_string(template_name, context) ("none", True)
def get_size(instance):
if hasattr(instance, "full_flavor"):
size_string = _("%(name)s | %(RAM)s RAM | %(VCPU)s VCPU "
"| %(disk)s Disk")
vals = {'name': instance.full_flavor.name,
'RAM': sizeformat.mbformat(instance.full_flavor.ram),
'VCPU': instance.full_flavor.vcpus,
'disk': sizeformat.diskgbformat(instance.full_flavor.disk)}
return size_string % vals
return _("Not available")
def get_power_state(instance):
return POWER_STATES.get(getattr(instance, "OS-EXT-STS:power_state", 0), '')
STATUS_DISPLAY_CHOICES = (
("resize", "Resize/Migrate"),
("verify_resize", "Confirm or Revert Resize/Migrate"),
("revert_resize", "Revert Resize/Migrate"),
) )
STATUS_CHOICES = (
("active", True),
TASK_DISPLAY_CHOICES = ( ("shutoff", True),
("image_snapshot", "Snapshotting"), ("error", False),
("resize_prep", "Preparing Resize or Migrate"),
("resize_migrating", "Resizing or Migrating"),
("resize_migrated", "Resized or Migrated"),
("resize_finish", "Finishing Resize or Migrate"),
("resize_confirming", "Confirming Resize or Nigrate"),
("resize_reverting", "Reverting Resize or Migrate"),
("unpausing", "Resuming"),
) )
name = tables.Column("name",
link=("horizon:project:windc:services"),
verbose_name=_("Name"))
class Meta:
name = "windc"
verbose_name = _("Windows Data Centers")
row_class = UpdateRow
table_actions = (CreateDataCenter,)
row_actions = (ShowDataCenterServices,)
class WinServicesTable(tables.DataTable): class WinServicesTable(tables.DataTable):
@ -202,29 +129,12 @@ class WinServicesTable(tables.DataTable):
("error", False), ("error", False),
) )
name = tables.Column("name", name = tables.Column("name",
link=("horizon:project:windc:detail"), link=("horizon:project:windc"),
verbose_name=_("Name")) verbose_name=_("Name"))
ip = tables.Column(get_ips, verbose_name=_("IP Address"))
size = tables.Column(get_size,
verbose_name=_("Type"),
attrs={'data-type': 'type'})
status = tables.Column("status",
filters=(title, replace_underscores),
verbose_name=_("Status"),
status=True,
status_choices=STATUS_CHOICES,
display_choices=STATUS_DISPLAY_CHOICES)
task = tables.Column("OS-EXT-STS:task_state",
verbose_name=_("Task"),
filters=(title, replace_underscores),
status=True,
status_choices=TASK_STATUS_CHOICES,
display_choices=TASK_DISPLAY_CHOICES)
class Meta: class Meta:
name = "windc" name = "services"
verbose_name = _("Windows Services") verbose_name = _("Services")
status_columns = ["status", "task"]
row_class = UpdateRow row_class = UpdateRow
table_actions = (CreateService, DeleteService) table_actions = (CreateService,)
row_actions = (EditService, RebootService) row_actions = (EditService,)

View File

@ -1,9 +1,9 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% load i18n %} {% load i18n %}
{% block title %}{% trans "Windows Services" %}{% endblock %} {% block title %}{% trans "Windows Data Centers" %}{% endblock %}
{% block page_header %} {% block page_header %}
{% include "horizon/common/_page_header.html" with title=_("Windows Services") %} {% include "horizon/common/_page_header.html" with title=_("Windows Data Centers") %}
{% endblock page_header %} {% endblock page_header %}
{% block main %} {% block main %}

View File

@ -20,12 +20,15 @@
from django.conf.urls.defaults import patterns, url from django.conf.urls.defaults import patterns, url
from .views import IndexView, CreateWinServiceView from .views import IndexView, CreateWinDCView, WinServices, CreateWinServiceView
VIEW_MOD = 'openstack_dashboard.dashboards.project.windc.views' VIEW_MOD = 'openstack_dashboard.dashboards.project.windc.views'
urlpatterns = patterns(VIEW_MOD, urlpatterns = patterns(VIEW_MOD,
url(r'^$', IndexView.as_view(), name='index'), url(r'^$', IndexView.as_view(), name='index'),
url(r'^create$', CreateWinServiceView.as_view(), name='create') url(r'^create$', CreateWinServiceView.as_view(), name='create'),
url(r'^create_dc$', CreateWinDCView.as_view(), name='create_dc'),
url(r'^(?P<domain_controller_id>[^/]+)/$', WinServices.as_view(),
name='services')
) )

View File

@ -15,8 +15,7 @@
# Unless required by applicable law or agreed to in writing, software # Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations# under the License.
# under the License.
""" """
Views for managing instances. Views for managing instances.
@ -36,51 +35,61 @@ from horizon import tables
from horizon import workflows from horizon import workflows
from openstack_dashboard import api from openstack_dashboard import api
from .tables import WinServicesTable from .tables import WinDCTable, WinServicesTable
from .workflows import CreateWinService from .tabs import WinServicesTab
from .workflows import CreateWinService, CreateWinDC
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
class IndexView(tables.DataTableView): class IndexView(tables.DataTableView):
table_class = WinServicesTable table_class = WinDCTable
template_name = 'project/windc/index.html' template_name = 'project/windc/index.html'
def get_data(self): def get_data(self):
# Gather our instances # Gather our instances
try: try:
instances = api.nova.server_list(self.request) data_centers = api.windc.datacenter_list(self.request)
except: except:
instances = [] data_centers = []
exceptions.handle(self.request, exceptions.handle(self.request,
_('Unable to retrieve instances.')) _('Unable to retrieve data centers list.'))
# Gather our flavors and correlate our instances to them return data_centers
if instances:
try:
flavors = api.nova.flavor_list(self.request)
except:
flavors = []
exceptions.handle(self.request, ignore=True)
full_flavors = SortedDict([(str(flavor.id), flavor)
for flavor in flavors])
# Loop through instances to get flavor info.
for instance in instances:
try:
flavor_id = instance.flavor["id"]
if flavor_id in full_flavors:
instance.full_flavor = full_flavors[flavor_id]
else:
# If the flavor_id is not in full_flavors list,
# get it via nova api.
instance.full_flavor = api.nova.flavor_get(
self.request, flavor_id)
except:
msg = _('Unable to retrieve instance size information.')
exceptions.handle(self.request, msg)
return instances
class WinServices(tables.DataTableView):
table_class = WinServicesTable
template_name = 'project/windc/services.html'
def get_context_data(self, **kwargs):
context = super(WinServices, self).get_context_data(**kwargs)
context["domain_controller_name"] = self.get_data()[0].name
return context
def get_data(self):
try:
dc_id = self.kwargs['domain_controller_id']
domain_controller = api.windc.datacenter_get(self.request, dc_id)
except:
redirect = reverse('horizon:project:windc:index')
exceptions.handle(self.request,
_('Unable to retrieve details for '
'domain_controller "%s".') % dc_id,
redirect=redirect)
self._domain_controller = [domain_controller,]
return self._domain_controller
class CreateWinDCView(workflows.WorkflowView):
workflow_class = CreateWinDC
template_name = "project/windc/create_dc.html"
def get_initial(self):
initial = super(CreateWinDCView, self).get_initial()
initial['project_id'] = self.request.user.tenant_id
initial['user_id'] = self.request.user.id
return initial
class CreateWinServiceView(workflows.WorkflowView): class CreateWinServiceView(workflows.WorkflowView):
workflow_class = CreateWinService workflow_class = CreateWinService

View File

@ -61,8 +61,22 @@ class SelectProjectUserAction(workflows.Action):
class SelectProjectUser(workflows.Step): class SelectProjectUser(workflows.Step):
action_class = SelectProjectUserAction action_class = SelectProjectUserAction
#contributes = ("project_id", "user_id")
class ConfigureDCAction(workflows.Action):
dc_name = forms.CharField(label=_("Data Center Name"),
required=True,
help_text=_("A name of new data center."))
class Meta:
name = _("Data Center")
help_text_template = ("project/windc/_data_center_help.html")
class ConfigureDC(workflows.Step):
action_class = ConfigureDCAction
class ConfigureWinDCAction(workflows.Action): class ConfigureWinDCAction(workflows.Action):
dc_name = forms.CharField(label=_("Domain Name"), dc_name = forms.CharField(label=_("Domain Name"),
required=False, required=False,
@ -129,11 +143,11 @@ class ConfigureWinIIS(workflows.Step):
class CreateWinService(workflows.Workflow): class CreateWinService(workflows.Workflow):
slug = "create" slug = "create"
name = _("Create Windows Service") name = _("Create Service")
finalize_button_name = _("Deploy") finalize_button_name = _("Deploy")
success_message = _('Deployed %(count)s named "%(name)s".') success_message = _('Deployed %(count)s named "%(name)s".')
failure_message = _('Unable to deploy %(count)s named "%(name)s".') failure_message = _('Unable to deploy %(count)s named "%(name)s".')
success_url = "horizon:project:windc:index" success_url = "horizon:project:windc:services"
default_steps = (SelectProjectUser, default_steps = (SelectProjectUser,
ConfigureWinDC, ConfigureWinDC,
ConfigureWinIIS) ConfigureWinIIS)
@ -148,3 +162,25 @@ class CreateWinService(workflows.Workflow):
# except: # except:
# exceptions.handle(request) # exceptions.handle(request)
# return False # return False
class CreateWinDC(workflows.Workflow):
slug = "create"
name = _("Create Windows Data Center")
finalize_button_name = _("Deploy")
success_message = _('Deployed %(count)s named "%(name)s".')
failure_message = _('Unable to deploy %(count)s named "%(name)s".')
success_url = "horizon:project:windc"
default_steps = (SelectProjectUser,
ConfigureDC)
## TO DO:
## Need to rewrite the following code:
#def handle(self, request, context):
# try:
# api.windc.create(request,...)
# return True
# except:
# exceptions.handle(request)
# return False