Merge ssh://gerrit.mirantis.com:29418/keero/keero into feature-orchestration
This commit is contained in:
@@ -35,27 +35,35 @@ def windcclient(request):
|
|||||||
% (request.user.token, url))
|
% (request.user.token, url))
|
||||||
return windc_client.Client(endpoint=url, token=None)
|
return windc_client.Client(endpoint=url, token=None)
|
||||||
|
|
||||||
|
|
||||||
def datacenters_create(request, parameters):
|
def datacenters_create(request, parameters):
|
||||||
name = parameters.get('name', '')
|
name = parameters.get('name', '')
|
||||||
return windcclient(request).datacenters.create(name)
|
return windcclient(request).datacenters.create(name)
|
||||||
|
|
||||||
|
|
||||||
def datacenters_delete(request, datacenter_id):
|
def datacenters_delete(request, datacenter_id):
|
||||||
return windcclient(request).datacenters.delete(datacenter_id)
|
return windcclient(request).datacenters.delete(datacenter_id)
|
||||||
|
|
||||||
|
|
||||||
def datacenters_get(request, datacenter_id):
|
def datacenters_get(request, datacenter_id):
|
||||||
return windcclient(request).datacenters.get(datacenter_id)
|
return windcclient(request).datacenters.get(datacenter_id)
|
||||||
|
|
||||||
|
|
||||||
def datacenters_list(request):
|
def datacenters_list(request):
|
||||||
return windcclient(request).datacenters.list()
|
return windcclient(request).datacenters.list()
|
||||||
|
|
||||||
|
|
||||||
def services_create(request, datacenter, parameters):
|
def services_create(request, datacenter, parameters):
|
||||||
return windcclient(request).services.create(datacenter, parameters)
|
return windcclient(request).services.create(datacenter, parameters)
|
||||||
|
|
||||||
|
|
||||||
def services_list(request, datacenter):
|
def services_list(request, datacenter):
|
||||||
return windcclient(request).services.list(datacenter)
|
return windcclient(request).services.list(datacenter)
|
||||||
|
|
||||||
|
|
||||||
def services_get(request, datacenter, service_id):
|
def services_get(request, datacenter, service_id):
|
||||||
return windcclient(request).services.get(datacenter, service_id)
|
return windcclient(request).services.get(datacenter, service_id)
|
||||||
|
|
||||||
|
|
||||||
def services_delete(request, datacenter, service_id):
|
def services_delete(request, datacenter, service_id):
|
||||||
return windcclient(request).services.delete(datacenter, service_id)
|
return windcclient(request).services.delete(datacenter, service_id)
|
||||||
|
@@ -20,19 +20,30 @@
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from django import forms
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from openstack_dashboard import api
|
from openstack_dashboard import api
|
||||||
|
|
||||||
from horizon import exceptions
|
|
||||||
from horizon import forms
|
from horizon import forms
|
||||||
|
from horizon import exceptions
|
||||||
from horizon import messages
|
from horizon import messages
|
||||||
|
|
||||||
|
import pdb
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class WizardFormServiceType(forms.Form):
|
||||||
|
_type = forms.ChoiceField(label=_("Service Type"))
|
||||||
|
|
||||||
|
|
||||||
|
class WizardFormConfiguration(forms.Form):
|
||||||
|
subject = forms.CharField(max_length=100)
|
||||||
|
sender = forms.CharField(max_length=1)
|
||||||
|
|
||||||
|
|
||||||
class UpdateWinDC(forms.SelfHandlingForm):
|
class UpdateWinDC(forms.SelfHandlingForm):
|
||||||
tenant_id = forms.CharField(widget=forms.HiddenInput)
|
tenant_id = forms.CharField(widget=forms.HiddenInput)
|
||||||
data_center = forms.CharField(widget=forms.HiddenInput)
|
data_center = forms.CharField(widget=forms.HiddenInput)
|
||||||
|
@@ -81,8 +81,7 @@ class DeleteDataCenter(tables.BatchAction):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def action(self, request, datacenter_id):
|
def action(self, request, datacenter_id):
|
||||||
datacenter = api.windc.datacenters_get(request, datacenter_id)
|
api.windc.datacenters_delete(request, datacenter_id)
|
||||||
api.windc.datacenters_delete(request, datacenter)
|
|
||||||
|
|
||||||
|
|
||||||
class DeleteService(tables.BatchAction):
|
class DeleteService(tables.BatchAction):
|
||||||
@@ -101,9 +100,8 @@ class DeleteService(tables.BatchAction):
|
|||||||
link = request.__dict__['META']['HTTP_REFERER']
|
link = request.__dict__['META']['HTTP_REFERER']
|
||||||
datacenter_id = re.search('windc/(\S+)', link).group(0)[6:-1]
|
datacenter_id = re.search('windc/(\S+)', link).group(0)[6:-1]
|
||||||
##############
|
##############
|
||||||
datacenter = api.windc.datacenters_get(request, datacenter_id)
|
|
||||||
|
|
||||||
api.windc.services_delete(request, datacenter, service_id)
|
api.windc.services_delete(request, datacenter_id, service_id)
|
||||||
|
|
||||||
|
|
||||||
class EditService(tables.LinkAction):
|
class EditService(tables.LinkAction):
|
||||||
@@ -116,6 +114,16 @@ class EditService(tables.LinkAction):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class Wizard(tables.LinkAction):
|
||||||
|
name = "wizard"
|
||||||
|
verbose_name = _("Wizard")
|
||||||
|
url = "horizon:project:windc:update"
|
||||||
|
classes = ("ajax-modal", "btn-edit")
|
||||||
|
|
||||||
|
def allowed(self, request, instance):
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
class ShowDataCenterServices(tables.LinkAction):
|
class ShowDataCenterServices(tables.LinkAction):
|
||||||
name = "edit"
|
name = "edit"
|
||||||
verbose_name = _("Services")
|
verbose_name = _("Services")
|
||||||
@@ -144,18 +152,36 @@ class WinDCTable(tables.DataTable):
|
|||||||
name = "windc"
|
name = "windc"
|
||||||
verbose_name = _("Windows Data Centers")
|
verbose_name = _("Windows Data Centers")
|
||||||
row_class = UpdateRow
|
row_class = UpdateRow
|
||||||
table_actions = (CreateDataCenter,)
|
table_actions = (CreateDataCenter, Wizard)
|
||||||
row_actions = (ShowDataCenterServices,DeleteDataCenter)
|
row_actions = (ShowDataCenterServices, DeleteDataCenter)
|
||||||
|
|
||||||
|
|
||||||
|
STATUS_DISPLAY_CHOICES = (
|
||||||
|
("create", "Deploy"),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class WinServicesTable(tables.DataTable):
|
class WinServicesTable(tables.DataTable):
|
||||||
name = tables.Column('dc_name', verbose_name=_('Name'))
|
|
||||||
|
STATUS_CHOICES = (
|
||||||
|
(None, True),
|
||||||
|
("deployed", True),
|
||||||
|
("active", True),
|
||||||
|
("error", False),
|
||||||
|
)
|
||||||
|
|
||||||
|
name = tables.Column('dc_name', verbose_name=_('Name'),
|
||||||
|
link=("horizon:project:windc:service_details"),)
|
||||||
_type = tables.Column('type', verbose_name=_('Type'))
|
_type = tables.Column('type', verbose_name=_('Type'))
|
||||||
status = tables.Column('status', verbose_name=_('Status'))
|
status = tables.Column('status', verbose_name=_('Status'),
|
||||||
|
status=True,
|
||||||
|
status_choices=STATUS_CHOICES,
|
||||||
|
display_choices=STATUS_DISPLAY_CHOICES)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
name = "services"
|
name = "services"
|
||||||
verbose_name = _("Services")
|
verbose_name = _("Services")
|
||||||
row_class = UpdateRow
|
row_class = UpdateRow
|
||||||
|
status_columns = ['status']
|
||||||
table_actions = (CreateService,)
|
table_actions = (CreateService,)
|
||||||
row_actions = (EditService, DeleteService)
|
row_actions = (EditService, DeleteService)
|
||||||
|
@@ -1,2 +1,3 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
<p>{% blocktrans %}You can deploy few domain controllers with one name.{% endblocktrans %}</p>
|
<p>{% blocktrans %}You can deploy few Active Directory services with one domain name.{% endblocktrans %}</p>
|
||||||
|
<p>{% blocktrans %}The DNS service will automatically created for each Active Directory.{% endblocktrans %}</p>
|
28
dashboard/windc/templates/windc/_services_tabs.html
Normal file
28
dashboard/windc/templates/windc/_services_tabs.html
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
{% extends "horizon/common/_modal_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% block modal-header %}{% trans "Create Service" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block modal-body %}
|
||||||
|
<p>Step {{ wizard.steps.step1 }} of {{ wizard.steps.count }}</p>
|
||||||
|
<form action="" method="post">{% csrf_token %}
|
||||||
|
<table>
|
||||||
|
{{ wizard.management_form }}
|
||||||
|
{% if wizard.form.forms %}
|
||||||
|
{{ wizard.form.management_form }}
|
||||||
|
{% for form in wizard.form.forms %}
|
||||||
|
{{ form }}
|
||||||
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
|
{{ wizard.form }}
|
||||||
|
{% endif %}
|
||||||
|
{{ wizard.form.forms }}
|
||||||
|
</table>
|
||||||
|
{% if wizard.steps.prev %}
|
||||||
|
<button name="wizard_goto_step" class="btn btn-small" type="submit" value="{{ wizard.steps.prev }}">{% trans "Back" %}</button>
|
||||||
|
<input type="submit" class="btn btn-primary pull-right" value="{% trans 'Deploy' %}"/>
|
||||||
|
{% else %}
|
||||||
|
<button name="wizard_goto_step" class="btn btn-small" type="submit" value="{{ wizard.steps.next }}">{% trans "Next" %}</button>
|
||||||
|
<input type="submit" class="btn btn-primary pull-right" value="{% trans 'Deploy' %}"/>
|
||||||
|
{% endif %}
|
||||||
|
</form>
|
||||||
|
{% endblock %}
|
@@ -20,8 +20,10 @@
|
|||||||
|
|
||||||
from django.conf.urls.defaults import patterns, url
|
from django.conf.urls.defaults import patterns, url
|
||||||
|
|
||||||
from .views import IndexView, CreateWinDCView, WinServices, CreateWinServiceView
|
from .views import IndexView, WinServices, \
|
||||||
|
CreateWinDCView, CreateWinServiceView
|
||||||
|
from .views import Wizard
|
||||||
|
from .forms import WizardFormServiceType, WizardFormConfiguration
|
||||||
|
|
||||||
VIEW_MOD = 'openstack_dashboard.dashboards.project.windc.views'
|
VIEW_MOD = 'openstack_dashboard.dashboards.project.windc.views'
|
||||||
|
|
||||||
@@ -29,6 +31,11 @@ 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'^create_dc$', CreateWinDCView.as_view(), name='create_dc'),
|
||||||
url(r'^(?P<domain_controller_id>[^/]+)/$', WinServices.as_view(),
|
url(r'^(?P<data_center_id>[^/]+)/$', WinServices.as_view(),
|
||||||
name='services')
|
name='services'),
|
||||||
|
url(r'^update$',
|
||||||
|
Wizard.as_view([WizardFormServiceType, WizardFormConfiguration]),
|
||||||
|
name='update'),
|
||||||
|
url(r'^(?P<service_id>[^/]+)/$', WinServices.as_view(),
|
||||||
|
name='service_details')
|
||||||
)
|
)
|
||||||
|
@@ -15,7 +15,8 @@
|
|||||||
# 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# under the License.
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Views for managing instances.
|
Views for managing instances.
|
||||||
@@ -24,24 +25,42 @@ import logging
|
|||||||
|
|
||||||
from django import http
|
from django import http
|
||||||
from django import shortcuts
|
from django import shortcuts
|
||||||
|
from django.views import generic
|
||||||
from django.core.urlresolvers import reverse, reverse_lazy
|
from django.core.urlresolvers import reverse, reverse_lazy
|
||||||
from django.utils.datastructures import SortedDict
|
from django.utils.datastructures import SortedDict
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
from django.contrib.formtools.wizard.views import SessionWizardView
|
||||||
|
|
||||||
from horizon import exceptions
|
from horizon import exceptions
|
||||||
from horizon import forms
|
from horizon import forms
|
||||||
from horizon import tabs
|
from horizon import tabs
|
||||||
from horizon import tables
|
from horizon import tables
|
||||||
from horizon import workflows
|
from horizon import workflows
|
||||||
|
from horizon.forms.views import ModalFormMixin
|
||||||
|
|
||||||
from openstack_dashboard import api
|
from openstack_dashboard import api
|
||||||
from .tables import WinDCTable, WinServicesTable
|
from .tables import WinDCTable, WinServicesTable
|
||||||
from .workflows import CreateWinService, CreateWinDC
|
from .workflows import CreateWinService, CreateWinDC
|
||||||
|
from .forms import WizardFormServiceType, WizardFormConfiguration
|
||||||
|
|
||||||
|
import pdb
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class Wizard(ModalFormMixin, SessionWizardView, generic.FormView):
|
||||||
|
template_name = 'project/windc/services_tabs.html'
|
||||||
|
|
||||||
|
def done(self, form_list, **kwargs):
|
||||||
|
#do_something_with_the_form_data(form_list)
|
||||||
|
return HttpResponseRedirect('/')
|
||||||
|
|
||||||
|
def get_form(self, step=None, data=None, files=None):
|
||||||
|
form = super(Wizard, self).get_form(step, data, files)
|
||||||
|
print step
|
||||||
|
print data
|
||||||
|
return form
|
||||||
|
|
||||||
|
|
||||||
class IndexView(tables.DataTableView):
|
class IndexView(tables.DataTableView):
|
||||||
table_class = WinDCTable
|
table_class = WinDCTable
|
||||||
template_name = 'project/windc/index.html'
|
template_name = 'project/windc/index.html'
|
||||||
@@ -69,7 +88,7 @@ class WinServices(tables.DataTableView):
|
|||||||
|
|
||||||
def get_data(self):
|
def get_data(self):
|
||||||
try:
|
try:
|
||||||
dc_id = self.kwargs['domain_controller_id']
|
dc_id = self.kwargs['data_center_id']
|
||||||
datacenter = api.windc.datacenters_get(self.request, dc_id)
|
datacenter = api.windc.datacenters_get(self.request, dc_id)
|
||||||
self.dc_name = datacenter.name
|
self.dc_name = datacenter.name
|
||||||
services = api.windc.services_list(self.request, datacenter)
|
services = api.windc.services_list(self.request, datacenter)
|
||||||
@@ -91,6 +110,7 @@ class CreateWinDCView(workflows.WorkflowView):
|
|||||||
initial['user_id'] = self.request.user.id
|
initial['user_id'] = self.request.user.id
|
||||||
return initial
|
return initial
|
||||||
|
|
||||||
|
|
||||||
class CreateWinServiceView(workflows.WorkflowView):
|
class CreateWinServiceView(workflows.WorkflowView):
|
||||||
workflow_class = CreateWinService
|
workflow_class = CreateWinService
|
||||||
template_name = "project/windc/create.html"
|
template_name = "project/windc/create.html"
|
||||||
|
@@ -84,11 +84,7 @@ class ConfigureWinDCAction(workflows.Action):
|
|||||||
dc_name = forms.CharField(label=_("Domain Name"),
|
dc_name = forms.CharField(label=_("Domain Name"),
|
||||||
required=False)
|
required=False)
|
||||||
|
|
||||||
#dc_net_name = forms.CharField(label=_("Domain NetBIOS Name"),
|
dc_count = forms.IntegerField(label=_("Instances Count"),
|
||||||
# required=False,
|
|
||||||
# help_text=_("A NetBIOS name of new domain."))
|
|
||||||
|
|
||||||
dc_count = forms.IntegerField(label=_("Domain Controllers Count"),
|
|
||||||
required=True,
|
required=True,
|
||||||
min_value=1,
|
min_value=1,
|
||||||
max_value=100,
|
max_value=100,
|
||||||
@@ -108,7 +104,7 @@ class ConfigureWinDCAction(workflows.Action):
|
|||||||
"Recovery Mode."))
|
"Recovery Mode."))
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
name = _("Domain Controllers")
|
name = _("Active Directory")
|
||||||
help_text_template = ("project/windc/_dc_help.html")
|
help_text_template = ("project/windc/_dc_help.html")
|
||||||
|
|
||||||
|
|
||||||
@@ -192,7 +188,6 @@ class CreateWinService(workflows.Workflow):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class CreateWinDC(workflows.Workflow):
|
class CreateWinDC(workflows.Workflow):
|
||||||
slug = "create"
|
slug = "create"
|
||||||
name = _("Create Windows Data Center")
|
name = _("Create Windows Data Center")
|
||||||
|
@@ -35,9 +35,9 @@ class DCManager(base.Manager):
|
|||||||
body.update(extra)
|
body.update(extra)
|
||||||
return self._create('/datacenters', body, 'datacenter')
|
return self._create('/datacenters', body, 'datacenter')
|
||||||
|
|
||||||
def delete(self, datacenter):
|
def delete(self, datacenter_id):
|
||||||
return self._delete("/datacenters/%s" % base.getid(datacenter))
|
return self._delete("/datacenters/%s" % datacenter_id)
|
||||||
|
|
||||||
def get(self, datacenter):
|
def get(self, datacenter_id):
|
||||||
return self._get("/datacenters/%s" % base.getid(datacenter),
|
return self._get("/datacenters/%s" % datacenter_id,
|
||||||
'datacenter')
|
'datacenter')
|
||||||
|
@@ -37,10 +37,9 @@ class DCServiceManager(base.Manager):
|
|||||||
return self._create("/datacenters/%s/services" % base.getid(datacenter),
|
return self._create("/datacenters/%s/services" % base.getid(datacenter),
|
||||||
body, 'service')
|
body, 'service')
|
||||||
|
|
||||||
def delete(self, datacenter, service):
|
def delete(self, datacenter_id, service_id):
|
||||||
return self._delete("/datacenters/%s/services/%s" % \
|
return self._delete("/datacenters/%s/services/%s" % \
|
||||||
(base.getid(datacenter),
|
(datacenter_id, service_id))
|
||||||
base.getid(service)))
|
|
||||||
|
|
||||||
def get(self, datacenter, service):
|
def get(self, datacenter, service):
|
||||||
return self._get("/datacenters/%s/services/%s" % \
|
return self._get("/datacenters/%s/services/%s" % \
|
||||||
|
82
tests/deploy.sh
Normal file
82
tests/deploy.sh
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
#!/usr/bin/expect -d
|
||||||
|
# The following directories should be created for this script:
|
||||||
|
# /opt/stack/devstack
|
||||||
|
# /opt/stack/keero
|
||||||
|
# the ssh key should be in directory /opt/stack/.ssh/
|
||||||
|
# the iso file with windows should be in directory /opt/stack/
|
||||||
|
|
||||||
|
set timeout 1200
|
||||||
|
|
||||||
|
send_user "\n\nStart to login to the test bed...\n\n"
|
||||||
|
|
||||||
|
spawn /usr/bin/ssh [lindex $argv 0]@[lindex $argv 1]
|
||||||
|
expect "password"
|
||||||
|
send -- "EVYiMCVZX9\n"
|
||||||
|
expect "*#*"
|
||||||
|
|
||||||
|
send -- "su - stack\n"
|
||||||
|
expect "*$*"
|
||||||
|
|
||||||
|
send -- "sudo killall python\n"
|
||||||
|
expect "*$*"
|
||||||
|
send -- "cd ~/devstack\n"
|
||||||
|
expect "*$*"
|
||||||
|
send -- "./unstack.sh\n"
|
||||||
|
expect "*$*"
|
||||||
|
send -- "./stack.sh\n"
|
||||||
|
expect "*Would you like to start it now?*"
|
||||||
|
send -- "y\n"
|
||||||
|
expect "*stack.sh completed*"
|
||||||
|
|
||||||
|
send -- "source openrc admin admin\n"
|
||||||
|
expect "*$*"
|
||||||
|
|
||||||
|
send -- "cd ~\n"
|
||||||
|
expect "*$*"
|
||||||
|
|
||||||
|
send -- "nova keypair-add keero-linux-keys > heat_key.priv\n"
|
||||||
|
expect "*$*"
|
||||||
|
|
||||||
|
send -- "glance image-create --name 'ws-2012-full-agent' --is-public true --container-format ovf --disk-format qcow2 < ws-2012-full-agent.qcow2\n"
|
||||||
|
expect "*$*"
|
||||||
|
|
||||||
|
send -- "cd ~/keero\n"
|
||||||
|
expect "*$*"
|
||||||
|
send -- "git pull\n"
|
||||||
|
expect "/.ssh/id_rsa"
|
||||||
|
send -- "swordfish\n"
|
||||||
|
expect "*$*"
|
||||||
|
send -- "cp -Rf ~/keero/dashboard/windc /opt/stack/horizon/openstack_dashboard/dashboards/project\n"
|
||||||
|
expect "*$*"
|
||||||
|
send -- "cp -f ~/keero/dashboard/api/windc.py /opt/stack/horizon/openstack_dashboard/api/\n"
|
||||||
|
expect "*$*"
|
||||||
|
send -- "cp -Rf ~/keero/dashboard/windcclient /opt/stack/horizon/\n"
|
||||||
|
expect "*$*"
|
||||||
|
send -- "cd ~/keero/windc\n"
|
||||||
|
expect "*$*"
|
||||||
|
send -- "rm -rf windc.sqlite\n"
|
||||||
|
expect "*$*"
|
||||||
|
send -- "./tools/with_venv.sh ./bin/windc-api --config-file=./etc/windc-api-paste.ini --dbsync\n"
|
||||||
|
expect "*$*"
|
||||||
|
send -- "logout\n"
|
||||||
|
expect "*#*"
|
||||||
|
|
||||||
|
send -- "rabbitmq-plugins enable rabbitmq_management\n"
|
||||||
|
expect "*#*"
|
||||||
|
send -- "service rabbitmq-server restart\n"
|
||||||
|
expect "*#*"
|
||||||
|
send -- "rabbitmqctl add_user keero keero\n"
|
||||||
|
expect "*#*"
|
||||||
|
send -- "rabbitmqctl set_user_tags keero administrator\n"
|
||||||
|
expect "*#*"
|
||||||
|
|
||||||
|
send -- "su - stack\n"
|
||||||
|
expect "*$*"
|
||||||
|
send -- "cd /opt/stack/devstack\n"
|
||||||
|
expect "*$*"
|
||||||
|
send -- "source openrc admin admin\n"
|
||||||
|
expect "*$*"
|
||||||
|
send -- "cd /opt/stack/keero/windc\n"
|
||||||
|
expect "*$*"
|
||||||
|
send -- "sudo ./tools/with_venv.sh ./bin/windc-api --config-file=./etc/windc-api-paste.ini > /opt/stack/tests_windc_daemon.log &\n"
|
||||||
|
expect "*$*"
|
4
tests/selenium/conf.ini
Normal file
4
tests/selenium/conf.ini
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
[server]
|
||||||
|
address=http://172.18.124.101
|
||||||
|
user=admin
|
||||||
|
password=AkvareL707
|
55
tests/selenium/datacenters_page.py
Normal file
55
tests/selenium/datacenters_page.py
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import re
|
||||||
|
from login_page import LoginPage
|
||||||
|
|
||||||
|
|
||||||
|
class DataCentersPage():
|
||||||
|
page = None
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
start_page = LoginPage()
|
||||||
|
self.page = start_page.login()
|
||||||
|
self.page.find_element_by_link_text('Project').click()
|
||||||
|
self.page.find_element_by_link_text('Windows Data Centers').click()
|
||||||
|
|
||||||
|
def create_data_center(self, name):
|
||||||
|
button_text = 'Create Windows Data Center'
|
||||||
|
self.page.find_element_by_link_text(button_text).click()
|
||||||
|
|
||||||
|
name_field = self.page.find_element_by_id('id_name')
|
||||||
|
xpath = "//input[@value='Create']"
|
||||||
|
button = self.page.find_element_by_xpath(xpath)
|
||||||
|
|
||||||
|
name_field.clear()
|
||||||
|
name_field.send_keys(name)
|
||||||
|
|
||||||
|
button.click()
|
||||||
|
|
||||||
|
return self.page
|
||||||
|
|
||||||
|
def find_data_center(self, name):
|
||||||
|
return self.page.find_element_by_link_text(name)
|
||||||
|
|
||||||
|
def delete_data_center(self, name):
|
||||||
|
datacenter = self.find_data_center(name)
|
||||||
|
link = datacenter.get_attribute('href')
|
||||||
|
datacenter_id = re.search('windc/(\S+)', link).group(0)[6:-1]
|
||||||
|
|
||||||
|
xpath = ".//*[@id='windc__row__%s']/td[3]/div/a[2]" % datacenter_id
|
||||||
|
more_button = self.page.find_element_by_xpath(xpath)
|
||||||
|
|
||||||
|
more_button.click()
|
||||||
|
|
||||||
|
delete_button_id = "windc__row_%s__action_delete" % datacenter_id
|
||||||
|
delete_button = self.page.find_element_by_id(delete_button_id)
|
||||||
|
|
||||||
|
delete_button.click()
|
||||||
|
|
||||||
|
self.page.find_element_by_link_text("Delete Data Center").click()
|
||||||
|
|
||||||
|
return self.page
|
||||||
|
|
||||||
|
def select_data_center(self, name):
|
||||||
|
datacenter = self.page.find_data_center(name)
|
||||||
|
datacenter.click()
|
||||||
|
|
||||||
|
return self.page
|
30
tests/selenium/login_page.py
Normal file
30
tests/selenium/login_page.py
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import ConfigParser
|
||||||
|
from selenium import webdriver
|
||||||
|
|
||||||
|
|
||||||
|
class LoginPage():
|
||||||
|
|
||||||
|
def login(self):
|
||||||
|
config = ConfigParser.RawConfigParser()
|
||||||
|
config.read('conf.ini')
|
||||||
|
url = config.get('server', 'address')
|
||||||
|
user = config.get('server', 'user')
|
||||||
|
password = config.get('server', 'password')
|
||||||
|
|
||||||
|
page = webdriver.Firefox()
|
||||||
|
page.set_page_load_timeout(30)
|
||||||
|
page.implicitly_wait(30)
|
||||||
|
page.get(url)
|
||||||
|
name = page.find_element_by_name('username')
|
||||||
|
pwd = page.find_element_by_name('password')
|
||||||
|
xpath = "//button[@type='submit']"
|
||||||
|
button = page.find_element_by_xpath(xpath)
|
||||||
|
|
||||||
|
name.clear()
|
||||||
|
name.send_keys(user)
|
||||||
|
pwd.clear()
|
||||||
|
pwd.send_keys(password)
|
||||||
|
|
||||||
|
button.click()
|
||||||
|
|
||||||
|
return page
|
55
tests/selenium/services_page.py
Normal file
55
tests/selenium/services_page.py
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import ConfigParser
|
||||||
|
from selenium import webdriver
|
||||||
|
|
||||||
|
|
||||||
|
class ServicesPage():
|
||||||
|
page = None
|
||||||
|
|
||||||
|
def __init__(self, page):
|
||||||
|
self.page = page
|
||||||
|
|
||||||
|
def create_service(self, service_type, parameters):
|
||||||
|
|
||||||
|
button_id = 'services__action_CreateService'
|
||||||
|
button = self.page.find_element_by_id(button_id)
|
||||||
|
button.click()
|
||||||
|
|
||||||
|
self.select_type_of_service(service_type)
|
||||||
|
|
||||||
|
for parameter in parameters:
|
||||||
|
field = self.page.find_element_by_name(parameter.key)
|
||||||
|
field.clear()
|
||||||
|
field.send_keys(parameter.value)
|
||||||
|
|
||||||
|
xpath = "//input[@value='Deploy']"
|
||||||
|
deploy_button = self.page.find_element_by_xpath(xpath)
|
||||||
|
deploy_button.click()
|
||||||
|
|
||||||
|
return page
|
||||||
|
|
||||||
|
def select_type_of_service(self, service_type):
|
||||||
|
tab = find_element_by_link_text(service_type)
|
||||||
|
tab.click()
|
||||||
|
return self.page
|
||||||
|
|
||||||
|
def find_service(self, name):
|
||||||
|
return self.page.find_element_by_link_text(name)
|
||||||
|
|
||||||
|
def delete_service(self, name):
|
||||||
|
service = self.find_data_center(name)
|
||||||
|
link = service.get_attribute('href')
|
||||||
|
|
||||||
|
service_id = re.search('windc/(\S+)', link).group(0)[6:-1]
|
||||||
|
|
||||||
|
xpath = ".//*[@id='services__row__%s']/td[5]/div/a[2]" % service_id
|
||||||
|
more_button = self.page.find_element_by_xpath(xpath)
|
||||||
|
more_button.click()
|
||||||
|
|
||||||
|
delete_button_id = "services__row_%s__action_delete" % datacenter_id
|
||||||
|
delete_button = self.page.find_element_by_id(delete_button_id)
|
||||||
|
|
||||||
|
delete_button.click()
|
||||||
|
|
||||||
|
self.page.find_element_by_link_text("Delete Service").click()
|
||||||
|
|
||||||
|
return self.page
|
35
tests/selenium/test.py
Normal file
35
tests/selenium/test.py
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import untitests
|
||||||
|
from datacenters_page import DataCentersPage
|
||||||
|
|
||||||
|
|
||||||
|
class SanityTests():
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.page = DataCentersPage()
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
self.page.close()
|
||||||
|
|
||||||
|
def test_01_create_data_center(self):
|
||||||
|
self.page.create_data_center('dc1')
|
||||||
|
assert self.page.find_data_center('dc1') is not None
|
||||||
|
|
||||||
|
def test_02_delete_data_center(self):
|
||||||
|
page.delete_data_center('dc1')
|
||||||
|
assert self.page.find_data_center('dc1') is None
|
||||||
|
|
||||||
|
def test_03_create_data_centers(self):
|
||||||
|
for i in range(1, 20):
|
||||||
|
name = 'datacenter' + str(i)
|
||||||
|
self.page.create_data_center(name)
|
||||||
|
assert self.page.find_data_center(name) is not None
|
||||||
|
|
||||||
|
def test_04_delete_data_centers(self):
|
||||||
|
page.delete_data_center('datacenter1')
|
||||||
|
page.delete_data_center('datacenter20')
|
||||||
|
assert self.page.find_data_center('datacenter1') is None
|
||||||
|
assert self.page.find_data_center('datacenter20') is None
|
||||||
|
|
||||||
|
for i in range(2, 19):
|
||||||
|
name = 'datacenter' + str(i)
|
||||||
|
assert self.page.find_data_center(name) is not None
|
Reference in New Issue
Block a user