summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dev_env.sh56
-rw-r--r--setup.py2
-rw-r--r--test-requirements.txt2
-rw-r--r--tuskar_ui/api/heat.py14
-rw-r--r--tuskar_ui/api/node.py6
-rw-r--r--tuskar_ui/api/tuskar.py35
-rw-r--r--tuskar_ui/infrastructure/images/tables.py6
-rw-r--r--tuskar_ui/infrastructure/images/views.py2
-rw-r--r--tuskar_ui/infrastructure/nodes/tests.py32
-rw-r--r--tuskar_ui/infrastructure/overview/forms.py3
-rw-r--r--tuskar_ui/infrastructure/overview/tests.py1
-rw-r--r--tuskar_ui/infrastructure/overview/urls.py3
-rw-r--r--tuskar_ui/infrastructure/overview/views.py44
-rw-r--r--tuskar_ui/infrastructure/parameters/forms.py6
-rw-r--r--tuskar_ui/infrastructure/roles/tests.py16
-rw-r--r--tuskar_ui/infrastructure/roles/views.py2
-rw-r--r--tuskar_ui/infrastructure/roles/workflows.py4
-rw-r--r--tuskar_ui/infrastructure/static/infrastructure/js/tuskar.deployment_live.js17
-rw-r--r--tuskar_ui/infrastructure/templates/infrastructure/_scripts.html1
-rw-r--r--tuskar_ui/infrastructure/templates/infrastructure/overview/deployment_base.html2
-rw-r--r--tuskar_ui/infrastructure/templates/infrastructure/overview/deployment_live.html55
-rw-r--r--tuskar_ui/infrastructure/templates/infrastructure/overview/overcloudrc.sh.template9
-rw-r--r--tuskar_ui/infrastructure/templatetags/context_selection.py41
-rw-r--r--tuskar_ui/test/api_tests/node_tests.py2
-rw-r--r--tuskar_ui/test/api_tests/tuskar_tests.py4
-rw-r--r--tuskar_ui/test/test_data/heat_data.py48
-rw-r--r--tuskar_ui/test/test_data/tuskar_data.py7
27 files changed, 281 insertions, 139 deletions
diff --git a/dev_env.sh b/dev_env.sh
new file mode 100644
index 00000000..020cc2a5
--- /dev/null
+++ b/dev_env.sh
@@ -0,0 +1,56 @@
+#!/bin/bash
+set -ex
+
+USAGE="Usage: `basename $0` <undercloud_ip> <undercloud_admin_password>"
+
+if [ "$#" -ne 2 ]; then
+ echo $USAGE
+ exit 1
+fi
+
+UNDERCLOUD_IP=$1
+UNDERCLOUD_ADMIN_PASSWORD=$2
+
+echo "Copying SSH key..."
+cp /home/stack/.ssh/id_rsa /root/.ssh/
+
+echo "Installing system requirements..."
+yum install -y git python-devel swig openssl-devel mysql-devel libxml2-devel libxslt-devel gcc gcc-c++
+easy_install pip nose
+
+echo "Cloning repos..."
+mkdir /opt/stack
+cd /opt/stack
+git clone git://github.com/openstack/horizon.git
+git clone git://github.com/openstack/python-tuskarclient.git
+git clone git://github.com/openstack/tuskar-ui.git
+git clone git://github.com/rdo-management/tuskar-ui-extras.git
+
+echo "Setting up repos..."
+cd horizon
+python tools/install_venv.py
+./run_tests.sh -V
+cp openstack_dashboard/local/local_settings.py.example openstack_dashboard/local/local_settings.py
+tools/with_venv.sh pip install -e ../python-tuskarclient/
+tools/with_venv.sh pip install -e ../tuskar-ui/
+tools/with_venv.sh pip install -e ../tuskar-ui-extras/
+cp ../tuskar-ui/_50_tuskar.py.example openstack_dashboard/local/enabled/_50_tuskar.py
+cp ../tuskar-ui-extras/_60_tuskar_boxes.py.example openstack_dashboard/local/enabled/_60_tuskar_boxes.py
+cp ../tuskar-ui/_10_admin.py.example openstack_dashboard/local/enabled/_10_admin.py
+cp ../tuskar-ui/_20_project.py.example openstack_dashboard/local/enabled/_20_project.py
+cp ../tuskar-ui/_30_identity.py.example openstack_dashboard/local/enabled/_30_identity.py
+sed -i s/'OPENSTACK_HOST = "127.0.0.1"'/'OPENSTACK_HOST = "192.0.2.1"'/ openstack_dashboard/local/local_settings.py
+echo 'IRONIC_DISCOVERD_URL = "http://%s:5050" % OPENSTACK_HOST' >> openstack_dashboard/local/local_settings.py
+echo 'UNDERCLOUD_ADMIN_PASSWORD = "'$UNDERCLOUD_ADMIN_PASSWORD'"' >> openstack_dashboard/local/local_settings.py
+echo 'DEPLOYMENT_MODE = "scale"' >> openstack_dashboard/local/local_settings.py
+
+echo "Setting up networking..."
+sudo ip route replace 192.0.2.0/24 dev virbr0 via $UNDERCLOUD_IP
+
+echo "Setting up iptables on the undercloud..."
+RULE_1="-A INPUT -p tcp -m tcp --dport 8585 -j ACCEPT"
+RULE_2="-A INPUT -p tcp -m tcp --dport 9696 -j ACCEPT"
+RULE_3="-A INPUT -p tcp -m tcp --dport 8777 -j ACCEPT"
+ssh $UNDERCLOUD_IP "sed -i '/$RULE_1/a $RULE_2' /etc/sysconfig/iptables"
+ssh $UNDERCLOUD_IP "sed -i '/$RULE_2/a $RULE_3' /etc/sysconfig/iptables"
+ssh $UNDERCLOUD_IP "service iptables restart"
diff --git a/setup.py b/setup.py
index 056c16c2..d8080d05 100644
--- a/setup.py
+++ b/setup.py
@@ -25,5 +25,5 @@ except ImportError:
pass
setuptools.setup(
- setup_requires=['pbr'],
+ setup_requires=['pbr>=1.3'],
pbr=True)
diff --git a/test-requirements.txt b/test-requirements.txt
index c2dedb5a..bc873bfc 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -20,7 +20,7 @@ http://tarballs.openstack.org/python-tuskarclient/python-tuskarclient-master.tar
coverage>=3.6
django-nose>=1.2
-mock>=1.0
+mock>=1.2
mox>=0.5.3
mox3>=0.7.0
nodeenv>=0.9.4 # BSD License
diff --git a/tuskar_ui/api/heat.py b/tuskar_ui/api/heat.py
index 9852ca00..923565ec 100644
--- a/tuskar_ui/api/heat.py
+++ b/tuskar_ui/api/heat.py
@@ -429,12 +429,14 @@ class Stack(base.APIResourceWrapper):
if not client:
return []
- services = client.services.list()
-
- for service in services:
- if service.name == 'horizon':
- break
- else:
+ try:
+ services = client.services.list()
+ for service in services:
+ if service.name == 'horizon':
+ break
+ else:
+ return []
+ except Exception:
return []
admin_urls = [endpoint.adminurl for endpoint
diff --git a/tuskar_ui/api/node.py b/tuskar_ui/api/node.py
index 2f67ae78..2ad65195 100644
--- a/tuskar_ui/api/node.py
+++ b/tuskar_ui/api/node.py
@@ -11,6 +11,7 @@
# under the License.
import logging
+import time
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
@@ -266,6 +267,11 @@ class Node(base.APIResourceWrapper):
for uuid in uuids:
discoverd_client.introspect(uuid, IRONIC_DISCOVERD_URL,
request.user.token.id)
+ # NOTE(dtantsur): PXE firmware on virtual machines misbehaves when
+ # a lot of nodes start DHCPing simultaneously: it ignores NACK from
+ # DHCP server, tries to get the same address, then times out. Work
+ # around it by using sleep, anyway introspection takes much longer.
+ time.sleep(5)
@classmethod
def set_maintenance(cls, request, uuid, maintenance):
diff --git a/tuskar_ui/api/tuskar.py b/tuskar_ui/api/tuskar.py
index 85d293eb..89244591 100644
--- a/tuskar_ui/api/tuskar.py
+++ b/tuskar_ui/api/tuskar.py
@@ -256,7 +256,7 @@ class Plan(base.APIResourceWrapper):
key_params = []
for role in self.role_list:
key_params.extend([role.node_count_parameter_name,
- role.image_id_parameter_name,
+ role.image_parameter_name,
role.flavor_parameter_name])
params = [p for p in params if p['name'] not in key_params]
return [Parameter(p, plan=self) for p in params]
@@ -389,9 +389,17 @@ class Role(base.APIResourceWrapper):
@classmethod
@memoized.memoized
- def _roles_by_image_id(cls, request, plan):
- return {plan.parameter_value(role.image_id_parameter_name): role
- for role in Role.list(request)}
+ def _roles_by_image(cls, request, plan):
+ roles_by_image = {}
+
+ for role in Role.list(request):
+ image = plan.parameter_value(role.image_parameter_name)
+ if image in roles_by_image:
+ roles_by_image[image].append(role)
+ else:
+ roles_by_image[image] = [role]
+
+ return roles_by_image
@classmethod
@handle_errors(_("Unable to retrieve overcloud role"))
@@ -411,11 +419,11 @@ class Role(base.APIResourceWrapper):
Role can be found
:rtype: tuskar_ui.api.tuskar.Role
"""
- roles = cls._roles_by_image_id(request, plan)
+ roles = cls._roles_by_image(request, plan)
try:
- return roles[image.id]
+ return roles[image.name]
except KeyError:
- return None
+ return []
@classmethod
@memoized.memoized
@@ -445,7 +453,7 @@ class Role(base.APIResourceWrapper):
return self.parameter_prefix + 'count'
@property
- def image_id_parameter_name(self):
+ def image_parameter_name(self):
return self.parameter_prefix + 'Image'
@property
@@ -453,12 +461,13 @@ class Role(base.APIResourceWrapper):
return self.parameter_prefix + 'Flavor'
def image(self, plan):
- image_id = plan.parameter_value(self.image_id_parameter_name)
- if image_id:
+ image_name = plan.parameter_value(self.image_parameter_name)
+ if image_name:
try:
- return glance.image_get(self._request, image_id)
- except glance_exceptions.HTTPNotFound:
- LOG.error("Couldn't obtain image with id %s" % image_id)
+ return glance.image_list_detailed(
+ self._request, filters={'name': image_name})[0][0]
+ except (glance_exceptions.HTTPNotFound, IndexError):
+ LOG.error("Couldn't obtain image with name %s" % image_name)
return None
def flavor(self, plan):
diff --git a/tuskar_ui/infrastructure/images/tables.py b/tuskar_ui/infrastructure/images/tables.py
index 8bd8bbf4..bbc8c0a9 100644
--- a/tuskar_ui/infrastructure/images/tables.py
+++ b/tuskar_ui/infrastructure/images/tables.py
@@ -61,9 +61,9 @@ class ImagesTable(tables.DataTable):
verbose_name=_("Image Name"))
disk_format = tables.Column('disk_format',
verbose_name=_("Format"))
- role = tables.Column(lambda image:
- image.role.name if image.role else '-',
- verbose_name=_("Deployment Role"))
+ roles = tables.Column(lambda image:
+ ', '.join([r.name for r in image.roles]),
+ verbose_name=_("Deployment Roles"))
class Meta(object):
name = "images"
diff --git a/tuskar_ui/infrastructure/images/views.py b/tuskar_ui/infrastructure/images/views.py
index b18e0634..198fdf43 100644
--- a/tuskar_ui/infrastructure/images/views.py
+++ b/tuskar_ui/infrastructure/images/views.py
@@ -57,7 +57,7 @@ class IndexView(infrastructure_views.ItemCountMixin,
plan = tuskar_api.tuskar.Plan.get_the_plan(self.request)
for image in images:
- image.role = tuskar_api.tuskar.Role.get_by_image(
+ image.roles = tuskar_api.tuskar.Role.get_by_image(
self.request, plan, image)
return images
diff --git a/tuskar_ui/infrastructure/nodes/tests.py b/tuskar_ui/infrastructure/nodes/tests.py
index 4f91bb9e..485a31b4 100644
--- a/tuskar_ui/infrastructure/nodes/tests.py
+++ b/tuskar_ui/infrastructure/nodes/tests.py
@@ -162,8 +162,8 @@ class NodesTests(test.BaseAdminViewTests):
'register_nodes-0-cpus': '1',
'register_nodes-0-memory_mb': '2',
'register_nodes-0-local_gb': '3',
- 'register_nodes-0-deployment_kernel': images[6].id,
- 'register_nodes-0-deployment_ramdisk': images[7].id,
+ 'register_nodes-0-deployment_kernel': images[3].id,
+ 'register_nodes-0-deployment_ramdisk': images[4].id,
'register_nodes-1-driver': 'pxe_ipmitool',
'register_nodes-1-ipmi_address': '127.0.0.2',
@@ -172,8 +172,8 @@ class NodesTests(test.BaseAdminViewTests):
'register_nodes-1-cpus': '4',
'register_nodes-1-memory_mb': '5',
'register_nodes-1-local_gb': '6',
- 'register_nodes-1-deployment_kernel': images[6].id,
- 'register_nodes-1-deployment_ramdisk': images[7].id,
+ 'register_nodes-1-deployment_kernel': images[3].id,
+ 'register_nodes-1-deployment_ramdisk': images[4].id,
}
with mock.patch('tuskar_ui.api.node.Node', **{
'spec_set': ['create', 'get_all_mac_addresses'],
@@ -198,8 +198,8 @@ class NodesTests(test.BaseAdminViewTests):
ipmi_username=u'username',
ipmi_password=u'password',
driver='pxe_ipmitool',
- deployment_kernel=images[6].id,
- deployment_ramdisk=images[7].id,
+ deployment_kernel=images[3].id,
+ deployment_ramdisk=images[4].id,
),
mock.call(
mock.ANY,
@@ -212,8 +212,8 @@ class NodesTests(test.BaseAdminViewTests):
ipmi_username=None,
ipmi_password=None,
driver='pxe_ipmitool',
- deployment_kernel=images[6].id,
- deployment_ramdisk=images[7].id,
+ deployment_kernel=images[3].id,
+ deployment_ramdisk=images[4].id,
),
])
@@ -234,8 +234,8 @@ class NodesTests(test.BaseAdminViewTests):
'register_nodes-0-cpus': '1',
'register_nodes-0-memory_mb': '2',
'register_nodes-0-local_gb': '3',
- 'register_nodes-0-deployment_kernel': images[6].id,
- 'register_nodes-0-deployment_ramdisk': images[7].id,
+ 'register_nodes-0-deployment_kernel': images[3].id,
+ 'register_nodes-0-deployment_ramdisk': images[4].id,
'register_nodes-1-driver': 'pxe_ipmitool',
'register_nodes-1-ipmi_address': '127.0.0.2',
@@ -244,8 +244,8 @@ class NodesTests(test.BaseAdminViewTests):
'register_nodes-1-cpus': '4',
'register_nodes-1-memory_mb': '5',
'register_nodes-1-local_gb': '6',
- 'register_nodes-1-deployment_kernel': images[6].id,
- 'register_nodes-1-deployment_ramdisk': images[7].id,
+ 'register_nodes-1-deployment_kernel': images[3].id,
+ 'register_nodes-1-deployment_ramdisk': images[4].id,
}
with mock.patch('tuskar_ui.api.node.Node', **{
'spec_set': ['create', 'get_all_mac_addresses'],
@@ -269,8 +269,8 @@ class NodesTests(test.BaseAdminViewTests):
ipmi_username=u'username',
ipmi_password=u'password',
driver='pxe_ipmitool',
- deployment_kernel=images[6].id,
- deployment_ramdisk=images[7].id,
+ deployment_kernel=images[3].id,
+ deployment_ramdisk=images[4].id,
),
mock.call(
mock.ANY,
@@ -283,8 +283,8 @@ class NodesTests(test.BaseAdminViewTests):
ipmi_username=None,
ipmi_password=None,
driver='pxe_ipmitool',
- deployment_kernel=images[6].id,
- deployment_ramdisk=images[7].id,
+ deployment_kernel=images[3].id,
+ deployment_ramdisk=images[4].id,
),
])
self.assertTemplateUsed(
diff --git a/tuskar_ui/infrastructure/overview/forms.py b/tuskar_ui/infrastructure/overview/forms.py
index ff78123e..77ff8c37 100644
--- a/tuskar_ui/infrastructure/overview/forms.py
+++ b/tuskar_ui/infrastructure/overview/forms.py
@@ -412,6 +412,9 @@ class PostDeployInit(horizon.forms.SelfHandlingForm):
"cinder": {
"password": plan.parameter_value(
controller_role.parameter_prefix + 'CinderPassword')},
+ "cinderv2": {
+ "password": plan.parameter_value(
+ controller_role.parameter_prefix + 'CinderPassword')},
"ec2": {
"password": plan.parameter_value(
controller_role.parameter_prefix + 'GlancePassword')},
diff --git a/tuskar_ui/infrastructure/overview/tests.py b/tuskar_ui/infrastructure/overview/tests.py
index 760f193c..20155c86 100644
--- a/tuskar_ui/infrastructure/overview/tests.py
+++ b/tuskar_ui/infrastructure/overview/tests.py
@@ -278,6 +278,7 @@ class OverviewTests(test.BaseAdminViewTests):
'path': '/',
'admin_path': '/admin'},
'cinder': {'password': None},
+ 'cinderv2': {'password': None},
'glance': {'password': None},
'swift': {'password': None,
'path': '/v1/AUTH_%(tenant_id)s',
diff --git a/tuskar_ui/infrastructure/overview/urls.py b/tuskar_ui/infrastructure/overview/urls.py
index 6e409a6b..35410d5d 100644
--- a/tuskar_ui/infrastructure/overview/urls.py
+++ b/tuskar_ui/infrastructure/overview/urls.py
@@ -32,4 +32,7 @@ urlpatterns = urls.patterns(
urls.url(r'^scale-out$',
views.ScaleOutView.as_view(),
name='scale_out'),
+ urls.url(r'^download-overcloudrc$',
+ views.download_overcloudrc_file,
+ name='download_overcloudrc'),
)
diff --git a/tuskar_ui/infrastructure/overview/views.py b/tuskar_ui/infrastructure/overview/views.py
index 970725c8..90f9fa37 100644
--- a/tuskar_ui/infrastructure/overview/views.py
+++ b/tuskar_ui/infrastructure/overview/views.py
@@ -13,14 +13,18 @@
# under the License.
import json
+import logging
+import urlparse
from django.core.urlresolvers import reverse
from django.core.urlresolvers import reverse_lazy
from django import http
+from django import shortcuts
import django.utils.text
from django.utils.translation import ugettext_lazy as _
import heatclient
import horizon.forms
+from horizon import messages
from tuskar_ui import api
from tuskar_ui.infrastructure.overview import forms
@@ -29,6 +33,8 @@ from tuskar_ui.infrastructure import views
INDEX_URL = 'horizon:infrastructure:overview:index'
+LOG = logging.getLogger(__name__)
+
def _steps_message(messages):
total_steps = len(messages)
@@ -218,6 +224,10 @@ class IndexView(horizon.forms.ModalFormView, views.StackMixin):
controller_role.parameter_prefix + 'AdminPassword')
context['dashboard_urls'] = stack.dashboard_urls
+ no_proxy = [urlparse.urlparse(url).hostname
+ for url in stack.dashboard_urls]
+ context['no_proxy'] = ",".join(no_proxy)
+ context['auth_url'] = stack.keystone_auth_url
else:
messages = forms.validate_plan(request, plan)
context['plan_messages'] = messages
@@ -344,3 +354,37 @@ class ScaleOutView(horizon.forms.ModalFormView, views.StackMixin):
'plan': plan,
})
return context
+
+
+def _get_openrc_credentials(request):
+ plan = api.tuskar.Plan.get_the_plan(request)
+ stack = api.heat.Stack.get_by_plan(request, plan)
+ no_proxy = [urlparse.urlparse(url).hostname
+ for url in stack.dashboard_urls]
+ controller_role = plan.get_role_by_name("Controller")
+ credentials = dict(tenant_name='admin',
+ auth_url=stack.keystone_auth_url,
+ admin_password=plan.parameter_value(
+ controller_role.parameter_prefix + 'AdminPassword'),
+ no_proxy=",".join(no_proxy))
+ return credentials
+
+
+def download_overcloudrc_file(request):
+ template = 'infrastructure/overview/overcloudrc.sh.template'
+ try:
+ context = _get_openrc_credentials(request)
+
+ response = shortcuts.render(request,
+ template,
+ context,
+ content_type="text/plain")
+ response['Content-Disposition'] = ('attachment; '
+ 'filename="overcloudrc"')
+ response['Content-Length'] = str(len(response.content))
+ return response
+
+ except Exception as e:
+ LOG.exception("Exception in DownloadOvercloudrcForm.")
+ messages.error(request, _('Error Downloading RC File: %s') % e)
+ return shortcuts.redirect(request.build_absolute_uri())
diff --git a/tuskar_ui/infrastructure/parameters/forms.py b/tuskar_ui/infrastructure/parameters/forms.py
index cc31df57..e0c0609d 100644
--- a/tuskar_ui/infrastructure/parameters/forms.py
+++ b/tuskar_ui/infrastructure/parameters/forms.py
@@ -136,7 +136,11 @@ class AdvancedEditServiceConfig(ServiceConfig):
def handle(self, request, data):
plan = api.tuskar.Plan.get_the_plan(self.request)
- data = self._sync_common_params_across_roles(plan, data)
+
+ # TODO(bcrochet): Commenting this out.
+ # For advanced config, we should have a whitelist of which params
+ # must be synced across roles.
+ # data = self._sync_common_params_across_roles(plan, data)
try:
plan.patch(request, plan.uuid, data)
diff --git a/tuskar_ui/infrastructure/roles/tests.py b/tuskar_ui/infrastructure/roles/tests.py
index 55cba9d8..d9ee2057 100644
--- a/tuskar_ui/infrastructure/roles/tests.py
+++ b/tuskar_ui/infrastructure/roles/tests.py
@@ -48,15 +48,15 @@ class RolesTest(test.BaseAdminViewTests):
plans = [api.tuskar.Plan(plan)
for plan in self.tuskarclient_plans.list()]
flavor = self.novaclient_flavors.first()
- image = self.glanceclient_images.first()
+ images = self.glanceclient_images.list()
with contextlib.nested(
patch('tuskar_ui.api.tuskar.Plan.list',
return_value=plans),
patch('tuskar_ui.api.tuskar.Role.list',
return_value=roles),
- patch('openstack_dashboard.api.glance.image_get',
- return_value=image),
+ patch('openstack_dashboard.api.glance.image_list_detailed',
+ return_value=[images]),
patch('tuskar_ui.api.flavor.Flavor.get_by_name',
return_value=flavor)):
res = self.client.get(INDEX_URL)
@@ -69,7 +69,7 @@ class RolesTest(test.BaseAdminViewTests):
plans = [api.tuskar.Plan(plan)
for plan in self.tuskarclient_plans.list()]
flavor = self.novaclient_flavors.first()
- image = self.glanceclient_images.first()
+ images = self.glanceclient_images.list()
stack = api.heat.Stack(TEST_DATA.heatclient_stacks.first())
with contextlib.nested(
@@ -83,8 +83,8 @@ class RolesTest(test.BaseAdminViewTests):
return_value=[]),
patch('tuskar_ui.api.tuskar.Plan.list',
return_value=plans),
- patch('openstack_dashboard.api.glance.image_get',
- return_value=image),
+ patch('openstack_dashboard.api.glance.image_list_detailed',
+ return_value=[images]),
patch('tuskar_ui.api.flavor.Flavor.get_by_name',
return_value=flavor)):
res = self.client.get(DETAIL_URL)
@@ -137,7 +137,7 @@ class RolesTest(test.BaseAdminViewTests):
'name': 'controller',
'description': 'The controller node role.',
'flavor': self.novaclient_flavors.first().name,
- 'image': self.glanceclient_images.first().id,
+ 'image': self.glanceclient_images.first().name,
'nodes': '0',
}
@@ -163,4 +163,4 @@ class RolesTest(test.BaseAdminViewTests):
args = mock_patch.call_args_list[0][0]
self.assertEqual(args[1], plan.id)
self.assertEqual(args[2]['Controller-1::Flavor'], u'flavor-1')
- self.assertEqual(args[2]['Controller-1::Image'], u'2')
+ self.assertEqual(args[2]['Controller-1::Image'], u'overcloud-full')
diff --git a/tuskar_ui/infrastructure/roles/views.py b/tuskar_ui/infrastructure/roles/views.py
index 78a73065..b5cb5801 100644
--- a/tuskar_ui/infrastructure/roles/views.py
+++ b/tuskar_ui/infrastructure/roles/views.py
@@ -143,7 +143,7 @@ class UpdateView(workflows.WorkflowView, views.StackMixin, views.RoleMixin):
role_flavor = '' if role_flavor is None else role_flavor.name
role_image = role.image(plan)
- role_image = '' if role_image is None else role_image.id
+ role_image = '' if role_image is None else role_image.name
free_nodes = len(api.node.Node.list(self.request, associated=False,
maintenance=False))
diff --git a/tuskar_ui/infrastructure/roles/workflows.py b/tuskar_ui/infrastructure/roles/workflows.py
index 2a138c10..b9786112 100644
--- a/tuskar_ui/infrastructure/roles/workflows.py
+++ b/tuskar_ui/infrastructure/roles/workflows.py
@@ -78,7 +78,7 @@ class UpdateRoleInfoAction(workflows.Action):
images = [image for image in images
if tuskar_utils.check_image_type(image,
'overcloud provisioning')]
- choices = [(i.id, i.name) for i in images]
+ choices = [(i.name, i.name) for i in images]
return [('', _('Unknown'))] + choices
def clean_nodes(self):
@@ -170,7 +170,7 @@ class UpdateRole(workflows.Workflow):
redirect=reverse_lazy(self.index_url))
parameters = data['parameters']
- parameters[role.image_id_parameter_name] = data['image']
+ parameters[role.image_parameter_name] = data['image']
parameters[role.node_count_parameter_name] = data['nodes']
if utils.matching_deployment_mode():
parameters[role.flavor_parameter_name] = data['flavor']
diff --git a/tuskar_ui/infrastructure/static/infrastructure/js/tuskar.deployment_live.js b/tuskar_ui/infrastructure/static/infrastructure/js/tuskar.deployment_live.js
new file mode 100644
index 00000000..22e4f2f5
--- /dev/null
+++ b/tuskar_ui/infrastructure/static/infrastructure/js/tuskar.deployment_live.js
@@ -0,0 +1,17 @@
+tuskar.deployment_live = (function () {
+ 'use strict';
+
+ var module = {};
+
+ module.init = function () {
+ $("#overcloudrc").on("hide.bs.collapse", function(){
+ $("span.overcloudrc").html('Show <i class="fa fa-angle-down"></i>');
+ });
+ $("#overcloudrc").on("show.bs.collapse", function(){
+ $("span.overcloudrc").html('Hide <i class="fa fa-angle-up"></i>');
+ });
+ };
+
+ horizon.addInitFunction(module.init);
+ return module;
+} ());
diff --git a/tuskar_ui/infrastructure/templates/infrastructure/_scripts.html b/tuskar_ui/infrastructure/templates/infrastructure/_scripts.html
index 61d91811..ff190f01 100644
--- a/tuskar_ui/infrastructure/templates/infrastructure/_scripts.html
+++ b/tuskar_ui/infrastructure/templates/infrastructure/_scripts.html
@@ -10,6 +10,7 @@
<script src='{{ STATIC_URL }}infrastructure/js/tuskar.edit_plan.js' type='text/javascript' charset='utf-8'></script>
<script src='{{ STATIC_URL }}infrastructure/js/tuskar.deployment_progress.js' type='text/javascript' charset='utf-8'></script>
<script src='{{ STATIC_URL }}infrastructure/js/tuskar.performance.js' type='text/javascript' charset='utf-8'></script>
+ <script src='{{ STATIC_URL }}infrastructure/js/tuskar.deployment_live.js' type='text/javascript' charset='utf-8'></script>
{% endblock %}
{% comment %} Tuskar-UI Client-side Templates (These should *not* be inside the "compress" tag.) {% endcomment %}
diff --git a/tuskar_ui/infrastructure/templates/infrastructure/overview/deployment_base.html b/tuskar_ui/infrastructure/templates/infrastructure/overview/deployment_base.html
index b8065a6d..04bf8eef 100644
--- a/tuskar_ui/infrastructure/templates/infrastructure/overview/deployment_base.html
+++ b/tuskar_ui/infrastructure/templates/infrastructure/overview/deployment_base.html
@@ -22,4 +22,6 @@
</div>
</div>
+{% block deployment-overcloudrc %}{% endblock %}
+
{% block templates %}{% endblock %}
diff --git a/tuskar_ui/infrastructure/templates/infrastructure/overview/deployment_live.html b/tuskar_ui/infrastructure/templates/infrastructure/overview/deployment_live.html
index 9d371641..af6dfa81 100644
--- a/tuskar_ui/infrastructure/templates/infrastructure/overview/deployment_live.html
+++ b/tuskar_ui/infrastructure/templates/infrastructure/overview/deployment_live.html
@@ -56,3 +56,58 @@
</a>
{% endblock %}
+
+{% block deployment-overcloudrc %}
+ <div class="clear"></div>
+ <div class="deployment-icon">
+ <i class="fa fa-key fa-3x fa-fw"></i>
+ </div>
+ <div class="deployment-box clearfix">
+ <h4>{% trans "Overcloudrc Information" %}</h4><a data-toggle="collapse" href="#overcloudrc" aria-expanded="false" aria-controls="overcloudrc" id="collapse-rc"><span class='overcloudrc'>{% trans "Show" %}<i class="fa fa-angle-down"></i></span></a>
+ <div class="collapse" id="overcloudrc">
+ <div class="row">
+ <div class="col-xs-4">NOVA_VERSION:</div>
+ <div class="col-xs-8">1.1</div>
+ </div>
+ <div class="row">
+ <div class="col-xs-4">OS_USERNAME:</div>
+ <div class="col-xs-8">admin</div>
+ </div>
+ <div class="row">
+ <div class="col-xs-4">OS_PASSWORD:</div>
+ <div class="col-xs-8">{{ admin_password }}</div>
+ </div>
+ <div class="row">
+ <div class="col-xs-4">OS_AUTH_URL:</div>
+ <div class="col-xs-8">{{ auth_url }}</div>
+ </div>
+ <div class="row">
+ <div class="col-xs-4">OS_TENANT_NAME:</div>
+ <div class="col-xs-8">admin</div>
+ </div>
+ <div class="row">
+ <div class="col-xs-4">COMPUTE_API_VERSION:</div>
+ <div class="col-xs-8">1.1</div>
+ </div>
+ <div class="row">
+ <div class="col-xs-4">OS_NO_CACHE:</div>
+ <div class="col-xs-8">True</div>
+ </div>
+ <div class="row">
+ <div class="col-xs-4">no_proxy:</div>
+ <div class="col-xs-8">{{ no_proxy }}</div>
+ </div>
+ <div class="row">
+ <div class="col-xs-4">{% trans "Download" %}</div>
+ <div class="col-xs-8">
+ <a
+ href="{% url 'horizon:infrastructure:overview:download_overcloudrc' %}"
+ class="btn btn-default"
+ >
+ <i class="fa fa-lg fa-download"></i> {% trans "Download" %}
+ </a>
+ </div>
+ </div>
+ </div>
+ </div>
+{% endblock %}
diff --git a/tuskar_ui/infrastructure/templates/infrastructure/overview/overcloudrc.sh.template b/tuskar_ui/infrastructure/templates/infrastructure/overview/overcloudrc.sh.template
new file mode 100644
index 00000000..5977bb37
--- /dev/null
+++ b/tuskar_ui/infrastructure/templates/infrastructure/overview/overcloudrc.sh.template
@@ -0,0 +1,9 @@
+#!/bin/bash
+export NOVA_VERSION=1.1
+export OS_AUTH_URL={{ auth_url }}
+export OS_TENANT_NAME="admin"
+export OS_USERNAME="admin"
+export OS_PASSWORD={{ admin_password }}
+export COMPUTE_API_VERSION=1.1
+export OS_NO_CACHE=True
+export no_proxy={{ no_proxy }}
diff --git a/tuskar_ui/infrastructure/templatetags/context_selection.py b/tuskar_ui/infrastructure/templatetags/context_selection.py
deleted file mode 100644
index 8b29d805..00000000
--- a/tuskar_ui/infrastructure/templatetags/context_selection.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from __future__ import absolute_import
-
-from django import template
-
-
-register = template.Library()
-
-# Overwrite the selector code from OpenStack Dashboard, so that the
-# selector doesn't appear.
-
-
-@register.simple_tag()
-def show_overview(*args, **kwargs):
- return '<span class="context-overview"></span>'
-
-
-@register.simple_tag()
-def show_domain_list(*args, **kwargs):
- return ''
-
-
-@register.simple_tag()
-def show_project_list(*args, **kwargs):
- return ''
-
-
-@register.simple_tag()
-def show_region_list(*args, **kwargs):
- return ''
diff --git a/tuskar_ui/test/api_tests/node_tests.py b/tuskar_ui/test/api_tests/node_tests.py
index 2589caab..7bde594b 100644
--- a/tuskar_ui/test/api_tests/node_tests.py
+++ b/tuskar_ui/test/api_tests/node_tests.py
@@ -158,4 +158,4 @@ class NodeAPITests(test.APITestCase):
return_value=([instance], False),
):
ret_val = api.node.Node(node).image_name
- self.assertEqual(ret_val, 'overcloud-control')
+ self.assertEqual(ret_val, 'overcloud-full')
diff --git a/tuskar_ui/test/api_tests/tuskar_tests.py b/tuskar_ui/test/api_tests/tuskar_tests.py
index 16526a81..3979bd73 100644
--- a/tuskar_ui/test/api_tests/tuskar_tests.py
+++ b/tuskar_ui/test/api_tests/tuskar_tests.py
@@ -108,8 +108,8 @@ class TuskarAPITests(test.APITestCase):
return_value=roles):
ret_val = api.tuskar.Role.get_by_image(
self.request, plan, image)
- self.assertIsInstance(ret_val, api.tuskar.Role)
- self.assertEqual(ret_val.name, 'Controller')
+ self.assertIsInstance(ret_val, list)
+ self.assertEqual(len(ret_val), 3)
def test_parameter_stripped_name(self):
plan = api.tuskar.Plan(self.tuskarclient_plans.first())
diff --git a/tuskar_ui/test/test_data/heat_data.py b/tuskar_ui/test/test_data/heat_data.py
index d99908fc..303bcc0a 100644
--- a/tuskar_ui/test/test_data/heat_data.py
+++ b/tuskar_ui/test/test_data/heat_data.py
@@ -202,75 +202,47 @@ def data(TEST):
TEST.glanceclient_images = test_data_utils.TestDataContainer()
image_1 = images.Image(
images.ImageManager(None),
- {'id': '2',
- 'name': 'overcloud-control',
- 'is_public': True,
- 'protected': False,
- 'properties': {
- 'type': 'overcloud provisioning'
- }})
- image_2 = images.Image(
- images.ImageManager(None),
{'id': '1',
- 'name': 'overcloud-compute',
- 'is_public': True,
- 'protected': False,
- 'properties': {
- 'type': 'overcloud provisioning'
- }})
- image_3 = images.Image(
- images.ImageManager(None),
- {'id': '3',
- 'name': 'Object Storage Image',
- 'is_public': True,
- 'protected': False,
- 'properties': {
- 'type': 'overcloud provisioning'
- }})
- image_4 = images.Image(
- images.ImageManager(None),
- {'id': '4',
- 'name': 'Block Storage Image',
+ 'name': 'overcloud-full',
'is_public': True,
'protected': False,
'properties': {
'type': 'overcloud provisioning'
}})
- image_5 = images.Image(
+ image_2 = images.Image(
images.ImageManager(None),
- {'id': '5',
+ {'id': '2',
'name': 'Discovery Ramdisk',
'is_public': True,
'protected': False,
'properties': {
'type': 'discovery ramdisk'
}})
- image_6 = images.Image(
+ image_3 = images.Image(
images.ImageManager(None),
- {'id': '6',
+ {'id': '3',
'name': 'Discovery Kernel',
'is_public': True,
'protected': False,
'properties': {
'type': 'discovery kernel'
}})
- image_7 = images.Image(
+ image_4 = images.Image(
images.ImageManager(None),
- {'id': '7',
+ {'id': '4',
'name': 'Baremetal Deployment Kernel',
'is_public': True,
'protected': False,
'properties': {
'type': 'deploy kernel'
}})
- image_8 = images.Image(
+ image_5 = images.Image(
images.ImageManager(None),
- {'id': '8',
+ {'id': '5',
'name': 'Baremetal Deployment Ramdisk',
'is_public': True,
'protected': False,
'properties': {
'type': 'deploy ramdisk'
}})
- TEST.glanceclient_images.add(image_1, image_2, image_3, image_4,
- image_5, image_6, image_7, image_8)
+ TEST.glanceclient_images.add(image_1, image_2, image_3, image_4, image_5)
diff --git a/tuskar_ui/test/test_data/tuskar_data.py b/tuskar_ui/test/test_data/tuskar_data.py
index c1913180..dae72f1c 100644
--- a/tuskar_ui/test/test_data/tuskar_data.py
+++ b/tuskar_ui/test/test_data/tuskar_data.py
@@ -29,7 +29,6 @@ def data(TEST):
'template': '',
'created_at': '2014-05-27T21:11:09Z',
'modified_at': '2014-05-30T21:11:09Z',
- 'uuid': '1234567890',
'roles': [
{
'uuid': 'role-1',
@@ -108,7 +107,7 @@ def data(TEST):
'description': 'Controller image ID',
'hidden': False,
'default': '',
- 'value': '2',
+ 'value': 'overcloud-full',
'parameter_type': 'string',
'constraints': [],
}, {
@@ -117,7 +116,7 @@ def data(TEST):
'description': 'Compute image ID',
'hidden': False,
'default': '',
- 'value': '1',
+ 'value': 'overcloud-full',
'parameter_type': 'string',
'constraints': [],
}, {
@@ -126,7 +125,7 @@ def data(TEST):
'description': 'Block storage image ID',
'hidden': False,
'default': '',
- 'value': '4',
+ 'value': 'overcloud-full',
'parameter_type': 'string',
'constraints': [],
}, {