diff --git a/dashboard/api/windc.py b/dashboard/api/windc.py index 16f289b..adf6059 100644 --- a/dashboard/api/windc.py +++ b/dashboard/api/windc.py @@ -24,7 +24,6 @@ import urlparse from django.utils.decorators import available_attrs from portasclient.v1.client import Client as windc_client - LOG = logging.getLogger(__name__) @@ -52,28 +51,78 @@ def datacenters_list(request): return windcclient(request).environments.list() +def datacenters_deploy(request, datacenter_id): + sessions = windcclient(request).sessions.list(datacenter_id) + for session in sessions: + if session.state == 'open': + session_id = session.id + if not session_id: + return "Sorry, nothing to deploy." + return windcclient(request).sessions.deploy(datacenter_id, session_id) + + +def datacenters_get_status(request, datacenter_id): + return datacenters_get(request, datacenter_id).status + + def services_create(request, datacenter, parameters): - return windcclient(request).services.create(datacenter, parameters) + session_id = windcclient(request).sessions.list(datacenter)[0].id + if parameters['service_type'] == 'Active Directory': + res = windcclient(request).activeDirectories.create(datacenter, + session_id, + parameters) + else: + res = windcclient(request).webServers.create(datacenter, + session_id, + parameters) + + return res -def services_list(request, datacenter): - LOG.critical("********************************") - LOG.critical(dir(windcclient(request))) - LOG.critical("********************************") - session_id = request.user.token.token['id'] - services = [] - services += windcclient(request).activeDirectories.list(datacenter, session_id) - #services += windcclient(request).webServers.list(datacenter) - +def services_list(request, datacenter_id): + session_id = None + sessions = windcclient(request).sessions.list(datacenter_id) + for s in sessions: + if s.state in ['open', 'deployed', 'deploying']: + session_id = s.id + + if session_id is None: + session_id = windcclient(request).sessions.configure(datacenter_id).id + + services = windcclient(request).activeDirectories.list(datacenter_id, + session_id) + services += windcclient(request).webServers.list(datacenter_id, session_id) + return services -def services_get(request, datacenter, service_id): - LOG.critical("********************************") - LOG.debug(parameters) - LOG.critical("********************************") - return windcclient(request).services.get(datacenter, service_id) +def services_get(request, datacenter_id, service_id): + services = services_list(request, datacenter_id) + + for service in services: + if service.id is service_id: + return service -def services_delete(request, datacenter, service_id): - return windcclient(request).services.delete(datacenter, service_id) +def services_delete(request, datacenter_id, service_id): + services = services_list(request, datacenter_id) + + session_id = None + sessions = windcclient(request).sessions.list(datacenter_id) + for session in sessions: + if session.state == 'open': + session_id = session.id + + if session_id is None: + raise Exception("Sorry, you can not delete this service now.") + + for service in services: + if service.id is service_id: + if service.type is 'Active Directory': + windcclient(request).activeDirectories.delete(datacenter_id, + session_id, + service_id) + elif service.type is 'IIS': + windcclient(request).webServers.delete(datacenter_id, + session_id, + service_id) diff --git a/dashboard/windc/forms.py b/dashboard/windc/forms.py index 7340fb2..b44cd16 100644 --- a/dashboard/windc/forms.py +++ b/dashboard/windc/forms.py @@ -19,6 +19,7 @@ # under the License. import logging +import string from django import forms from django.core.urlresolvers import reverse @@ -30,82 +31,90 @@ from horizon import forms from horizon import exceptions from horizon import messages -import pdb - LOG = logging.getLogger(__name__) +class PasswordField(forms.CharField): + + # Setup the Field + def __init__(self, label, *args, **kwargs): + super(PasswordField, self).__init__(min_length=7, required=True, + label=label, + widget=forms.PasswordInput(render_value=False), + *args, **kwargs) + + def clean(self, value): + + # Setup Our Lists of Characters and Numbers + characters = list(string.letters) + special_characters = '!@#$%^&*()_+|\/.,~?><:{}' + numbers = [str(i) for i in range(10)] + + # Assume False until Proven Otherwise + numCheck = False + charCheck = False + specCharCheck = False + + # Loop until we Match + for char in value: + if not charCheck: + if char in characters: + charCheck = True + if not specCharCheck: + if char in special_characters: + specCharCheck = True + if not numCheck: + if char in numbers: + numCheck = True + if numCheck and charCheck and specCharCheck: + break + + if not numCheck or not charCheck or not specCharCheck: + raise forms.ValidationError(u'Your password must include at least \ + one letter, at least one number and \ + at least one special character.') + + return super(PasswordField, self).clean(value) + + class WizardFormServiceType(forms.Form): - service = forms.ChoiceField(label=_("Service Type"), + service = forms.ChoiceField(label=_('Service Type'), choices=[ - ('active directory', 'Active Directory'), - ('iis', 'Internet Information Services') + ('Active Directory', 'Active Directory'), + ('IIS', 'Internet Information Services') ]) class WizardFormConfiguration(forms.Form): - "The functions for this class will dynamically create in views.py" + 'The functions for this class will dynamically create in views.py' pass class WizardFormADConfiguration(forms.Form): - dc_name = forms.CharField(label=_("Domain Name"), - required=False) + dc_name = forms.CharField(label=_('Domain Name'), + required=True) - dc_count = forms.IntegerField(label=_("Instances Count"), + dc_count = forms.IntegerField(label=_('Instances Count'), required=True, min_value=1, max_value=100, initial=1) - adm_password = forms.CharField(widget=forms.PasswordInput, - label=_("Administrator password"), - required=False) + adm_password = PasswordField(_('Administrator password')) - recovery_password = forms.CharField(widget=forms.PasswordInput, - label=_("Recovery password"), - required=False) + recovery_password = PasswordField(_('Recovery password')) class WizardFormIISConfiguration(forms.Form): - iis_name = forms.CharField(label=_("IIS Server Name"), - required=False) + iis_name = forms.CharField(label=_('IIS Server Name'), + required=True) - adm_password = forms.CharField(widget=forms.PasswordInput, - label=_("Administrator password"), - required=False) + adm_password = PasswordField(_('Administrator password')) - iis_count = forms.IntegerField(label=_("IIS Servers Count"), - required=True, - min_value=1, - max_value=100, - initial=1) + iis_domain = forms.CharField(label=_('Member of the Domain'), + required=True) - iis_domain = forms.CharField(label=_("Member of the Domain"), - required=False) + domain_user_name = forms.CharField(label=_('Domain User Name'), + required=True) - domain_user_name = forms.CharField(label=_("Domain User Name"), - required=False) - - domain_user_password = forms.CharField(widget=forms.PasswordInput, - label=_("Domain User Password"), - required=False) - - -class UpdateWinDC(forms.SelfHandlingForm): - tenant_id = forms.CharField(widget=forms.HiddenInput) - data_center = forms.CharField(widget=forms.HiddenInput) - name = forms.CharField(required=True) - - def handle(self, request, data): - try: - server = api.nova.server_update(request, data['data_center'], - data['name']) - messages.success(request, - _('Data Center "%s" updated.') % data['name']) - return server - except: - redirect = reverse("horizon:project:windc:index") - exceptions.handle(request, - _('Unable to update data center.'), - redirect=redirect) + domain_user_password = PasswordField(_('Domain User Password')) diff --git a/dashboard/windc/tables.py b/dashboard/windc/tables.py index a5c7b4d..97fe9bc 100644 --- a/dashboard/windc/tables.py +++ b/dashboard/windc/tables.py @@ -43,24 +43,23 @@ LOG = logging.getLogger(__name__) class CreateService(tables.LinkAction): - name = "CreateService" - verbose_name = _("Create Service") - url = "horizon:project:windc:create" - classes = ("btn-launch", "ajax-modal") + name = 'CreateService' + verbose_name = _('Create Service') + url = 'horizon:project:windc:create' + classes = ('btn-launch', 'ajax-modal') def allowed(self, request, datum): return True def action(self, request, service): - # FIX ME api.windc.services_create(request, service) class CreateDataCenter(tables.LinkAction): - name = "CreateDataCenter" - verbose_name = _("Create Windows Data Center") - url = "horizon:project:windc:create_dc" - classes = ("btn-launch", "ajax-modal") + 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 @@ -70,11 +69,11 @@ class CreateDataCenter(tables.LinkAction): class DeleteDataCenter(tables.BatchAction): - name = "delete" - action_present = _("Delete") - action_past = _("Delete") - data_type_singular = _("Data Center") - data_type_plural = _("Data Center") + name = 'delete' + action_present = _('Delete') + action_past = _('Delete') + data_type_singular = _('Data Center') + data_type_plural = _('Data Center') classes = ('btn-danger', 'btn-terminate') def allowed(self, request, datum): @@ -85,93 +84,128 @@ class DeleteDataCenter(tables.BatchAction): class DeleteService(tables.BatchAction): - name = "delete" - action_present = _("Delete") - action_past = _("Delete") - data_type_singular = _("Service") - data_type_plural = _("Service") + name = 'delete' + action_present = _('Delete') + action_past = _('Delete') + data_type_singular = _('Service') + data_type_plural = _('Service') classes = ('btn-danger', 'btn-terminate') def allowed(self, request, datum): return True def action(self, request, service_id): - ############## FIX ME: link = request.__dict__['META']['HTTP_REFERER'] datacenter_id = re.search('windc/(\S+)', link).group(0)[6:-1] - ############## - api.windc.services_delete(request, datacenter_id, service_id) + try: + api.windc.services_delete(request, datacenter_id, service_id) + except: + messages.error(request, + _('Sorry, you can not delete this service right now.')) -class EditService(tables.LinkAction): - name = "edit" - verbose_name = _("Edit") - url = "horizon:project:windc:update" - classes = ("ajax-modal", "btn-edit") +class DeployDataCenter(tables.BatchAction): + name = 'deploy' + action_present = _('Deploy') + action_past = _('Deploy') + data_type_singular = _('Data Center') + data_type_plural = _('Data Center') + classes = ('btn-launch') - def allowed(self, request, instance): + def allowed(self, request, datum): return True + def action(self, request, datacenter_id): + return api.windc.datacenters_deploy(request, datacenter_id) + class ShowDataCenterServices(tables.LinkAction): - name = "edit" - verbose_name = _("Services") - url = "horizon:project:windc:services" + name = 'edit' + verbose_name = _('Services') + url = 'horizon:project:windc:services' def allowed(self, request, instance): return True -class UpdateRow(tables.Row): +class UpdateDCRow(tables.Row): ajax = True - def get_data(self, request, instance_id): - instance = api.nova.server_get(request, instance_id) - instance.full_flavor = api.nova.flavor_get(request, - instance.flavor["id"]) - return instance + def get_data(self, request, datacenter_id): + return api.windc.datacenters_get(request, datacenter_id) + + +class UpdateServiceRow(tables.Row): + ajax = True + def get_data(self, request, service_id): + link = request.__dict__['META']['HTTP_REFERER'] + datacenter_id = re.search('windc/(\S+)', link).group(0)[6:-1] -class WinDCTable(tables.DataTable): - 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, DeleteDataCenter) + return api.windc.services_get(request, datacenter_id, service_id) STATUS_DISPLAY_CHOICES = ( - ("create", "Deploy"), + ('draft', 'Ready to deploy'), + ('pending', 'Wait for configuration'), + ('inprogress', 'Deploy in progress'), + ('finished', 'Active') ) +STATUS_CHOICES = ( + (None, True), + ('Ready to deploy', False), + ('Wait for configuration', True), + ('Deploy in progress', True), + ('Active', False), + ('error', False), +) -class WinServicesTable(tables.DataTable): +def get_datacenter_status(datacenter): + return datacenter.status - STATUS_CHOICES = ( - (None, True), - ("deployed", True), - ("active", True), - ("error", False), - ) +def get_service_status(service): + return service.status - name = tables.Column('dc_name', verbose_name=_('Name'), - link=("horizon:project:windc:service_details"),) - _type = tables.Column('type', verbose_name=_('Type')) - status = tables.Column('status', verbose_name=_('Status'), + +class WinDCTable(tables.DataTable): + + name = tables.Column('name', + link=('horizon:project:windc:services'), + verbose_name=_('Name')) + + status = tables.Column(get_datacenter_status, verbose_name=_('Status'), status=True, status_choices=STATUS_CHOICES, display_choices=STATUS_DISPLAY_CHOICES) class Meta: - name = "services" - verbose_name = _("Services") - row_class = UpdateRow + name = 'windc' + verbose_name = _('Windows Data Centers') + row_class = UpdateDCRow status_columns = ['status'] + table_actions = (CreateDataCenter,) + row_actions = (ShowDataCenterServices, DeleteDataCenter, + DeployDataCenter) + + +class WinServicesTable(tables.DataTable): + + name = tables.Column('name', verbose_name=_('Name'), + link=('horizon:project:windc:service_details'),) + + _type = tables.Column('service_type', verbose_name=_('Type')) + + status = tables.Column(get_service_status, verbose_name=_('Status'), + status=True, + status_choices=STATUS_CHOICES, + display_choices=STATUS_DISPLAY_CHOICES) + + class Meta: + name = 'services' + verbose_name = _('Services') + status_columns = ['status'] + row_class = UpdateServiceRow table_actions = (CreateService,) - row_actions = (EditService, DeleteService) + row_actions = (DeleteService,) diff --git a/dashboard/windc/templates/windc/_services_tabs.html b/dashboard/windc/templates/windc/_services_tabs.html index a00c4c3..a58eac8 100644 --- a/dashboard/windc/templates/windc/_services_tabs.html +++ b/dashboard/windc/templates/windc/_services_tabs.html @@ -7,6 +7,11 @@ {% block modal-header %}{% trans "Create Service" %}{% endblock %} {% block modal-body %} +
+
+{% if wizard.steps.next %} +


+{% endif %} {{ wizard.management_form }} {% if wizard.form.forms %} @@ -19,13 +24,35 @@ {% endif %} {{ wizard.form.forms }}
+
+
+ {% if wizard.steps.prev %} +

{{ service_type }} Service

+ {% if service_type == 'Active Directory' %} +

{% trans "Now you can set the parameters for Active Directory Service." %}

+

{% trans "You can create few Active Directory instances, in this case will be created one Main Active Directory server and few Secondary Active Directory servers." %}

+

{% trans "The DNS service will be automatically created on each Active Directory servers." %}

+ {% else %} +

{% trans "Now you can set parameters for IIS Service." %}

+

{% trans "The IIS Service - it is the server with complex Internet Information Services infrastructure, which included to the domain infrasructure." %}

+

{% trans "Please, set the complex password for local administrator account." %}

+

{% trans "Also, you can add this IIS server to the existing domain and configure credentials for domain user." %}

+ {% endif %} + + {% else %} +

{% trans "Description" %}:

+

{% trans "Now you can select the type of the service." %}

+

{% trans "The Active Directory Service allows to configure Domain Controllers with Active Directory and DNS infrastructure. You can create one Main Domain Controller and few Secondary Domain Controllers." %}

+

{% trans "The Internet Information Services allows to configure IIS servers, which can be included to the existing domain infrastructure." %}

+ {% endif %} +
{% endblock %} {% block modal-footer %} {% if wizard.steps.prev %} - - + + {% else %} - + {% endif %} {% endblock %} diff --git a/dashboard/windc/views.py b/dashboard/windc/views.py index acbd23c..626e73f 100644 --- a/dashboard/windc/views.py +++ b/dashboard/windc/views.py @@ -60,25 +60,45 @@ class Wizard(ModalFormMixin, SessionWizardView, generic.FormView): url = "/project/windc/%s/" % datacenter_id service_type = form_list[0].data.get('0-service', '') - parameters = {} - if form_list[1].data: - data = form_list[1].data + parameters = {'service_type': service_type} - if service_type == 'active directory': - parameters['dc_name'] = str(data.get('1-dc_name', 'noname')) - parameters['adm_password'] = str(data.get('1-adm_password', '')) - parameters['dc_count'] = int(data.get('1-dc_count', 1)) - parameters['recovery_password'] = \ - str(data.get('1-recovery_password', '')) - elif service_type == 'iis': - parameters['iis_name'] = str(data.get('1-iis_name', 'noname')) - parameters['adm_password'] = str(data.get('1-adm_password', '')) - parameters['iis_count'] = int(data.get('1-iis_count', 1)) - parameters['iis_domain'] = str(data.get('1-iis_domain', '')) - parameters['domain_user_name'] = \ - str(data.get('1-domain_user_name', '')) - parameters['domain_user_password'] = \ - str(data.get('1-domain_user_password', '')) + if service_type == 'Active Directory': + parameters['configuration'] = 'standalone' + parameters['name'] = str(form_list[1].data.get('1-dc_name', + 'noname')) + parameters['adminPassword'] = \ + str(form_list[1].data.get('1-adm_password', '')) + dc_count = int(form_list[1].data.get('1-dc_count', 1)) + recovery_password = \ + str(form_list[1].data.get('1-recovery_password', '')) + parameters['units'] = [] + parameters['units'].append({'isMaster': True, + 'recoveryPassword': recovery_password, + 'location': 'west-dc'}) + for dc in range(dc_count - 1): + parameters['units'].append({'isMaster': False, + 'recoveryPassword': recovery_password, + 'location': 'west-dc'}) + + elif service_type == 'IIS': + password = form_list[1].data.get('1-adm_password', '') + domain = form_list[1].data.get('1-iis_domain', '') + dc_user = form_list[1].data.get('1-domain_user_name', '') + dc_pass = form_list[1].data.get('1-domain_user_password', '') + parameters['name'] = str(form_list[1].data.get('1-iis_name', + 'noname')) + parameters['domain'] = parameters['name'] + parameters['credentials'] = {'username': 'Administrator', + 'password': password} + parameters['domain'] = str(domain) + # 'username': str(dc_user), + # 'password': str(dc_pass)} + parameters['location'] = 'west-dc' + + parameters['units'] = [] + parameters['units'].append({'id': '1', + 'endpoint': [{'host': '10.0.0.1'}], + 'location': 'west-dc'}) service = api.windc.services_create(self.request, datacenter_id, @@ -90,26 +110,37 @@ class Wizard(ModalFormMixin, SessionWizardView, generic.FormView): def get_form(self, step=None, data=None, files=None): form = super(Wizard, self).get_form(step, data, files) - LOG.debug("********" + str(self.form_list)) if data: service_type = data.get('0-service', '') - - if service_type == 'active directory': + self.service_type = service_type + if service_type == 'Active Directory': self.form_list['1'] = WizardFormADConfiguration - elif service_type == 'iis': + elif service_type == 'IIS': self.form_list['1'] = WizardFormIISConfiguration return form + def get_form_step_data(self, form): + LOG.debug(form.data) + return form.data + + def get_context_data(self, form, **kwargs): + context = super(Wizard, self).get_context_data(form=form, **kwargs) + if self.steps.index > 0: + context.update({'service_type': self.service_type}) + return context + class IndexView(tables.DataTableView): table_class = WinDCTable template_name = 'project/windc/index.html' def get_data(self): - # Gather our datacenters try: data_centers = api.windc.datacenters_list(self.request) + for dc in data_centers: + dc.status = api.windc.datacenters_get_status(self.request, + dc.id) except: data_centers = [] exceptions.handle(self.request, @@ -124,7 +155,7 @@ class WinServices(tables.DataTableView): def get_context_data(self, **kwargs): context = super(WinServices, self).get_context_data(**kwargs) data = self.get_data() - context["dc_name"] = self.dc_name + context['dc_name'] = self.dc_name return context def get_data(self): @@ -132,7 +163,7 @@ class WinServices(tables.DataTableView): dc_id = self.kwargs['data_center_id'] datacenter = api.windc.datacenters_get(self.request, dc_id) self.dc_name = datacenter.name - services = api.windc.services_list(self.request, datacenter) + services = api.windc.services_list(self.request, dc_id) except: services = [] exceptions.handle(self.request, @@ -143,7 +174,7 @@ class WinServices(tables.DataTableView): class CreateWinDCView(workflows.WorkflowView): workflow_class = CreateWinDC - template_name = "project/windc/create_dc.html" + template_name = 'project/windc/create_dc.html' def get_initial(self): initial = super(CreateWinDCView, self).get_initial()