Ladislav Smola 954262f557 Setup swift endpoint correctly
Swift needs different path that is currently in the
os-cloud-config default. This prevented Overcloud
Swift from working.

Change-Id: I8b8841c6fcc543e99642fd681b5d189b712e58a3
2014-10-10 11:14:48 +02:00

345 lines
14 KiB
Python

# -*- coding: utf8 -*-
#
# 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.
import logging
from django.core.urlresolvers import reverse_lazy
import django.forms
from django.utils.translation import ugettext_lazy as _
import horizon.exceptions
import horizon.forms
import horizon.messages
from neutronclient.common import exceptions as neutron_exceptions
from os_cloud_config import keystone as keystone_config
from os_cloud_config import neutron as neutron_config
from os_cloud_config.utils import clients
from tuskar_ui import api
import tuskar_ui.api.heat
import tuskar_ui.api.tuskar
import tuskar_ui.forms
LOG = logging.getLogger(__name__)
def validate_plan(request, plan):
"""Validates the plan and returns a list of dicts describing the issues."""
messages = []
try:
controller_role = plan.get_role_by_name("controller")
except KeyError:
messages.append({
'text': _(u"No controller role."),
'is_critical': True,
})
else:
if plan.get_role_node_count(controller_role) not in (1, 3):
messages.append({
'text': _(u"You should have either 1 or 3 controller nodes."),
'is_critical': True,
})
try:
compute_role = plan.get_role_by_name("compute")
except KeyError:
messages.append({
'text': _(u"No compute role."),
'is_critical': True,
})
else:
if plan.get_role_node_count(compute_role) < 1:
messages.append({
'text': _(u"You need at least 1 compute node."),
'is_critical': True,
})
requested_nodes = 0
previous_snmp_password = None
for role in plan.role_list:
if role.image(plan) is None:
messages.append({
'text': _(u"Role {0} has no image.").format(role.name),
'is_critical': False,
'link_url': reverse_lazy('horizon:infrastructure:roles:index'),
'link_label': _(u"Associate this role with an image."),
})
if role.flavor(plan) is None:
messages.append({
'text': _(u"Role {0} has no flavor.").format(role.name),
'is_critical': False,
'link_url': reverse_lazy('horizon:infrastructure:roles:index'),
'link_label': _(u"Associate this role with a flavor."),
})
requested_nodes += plan.get_role_node_count(role)
snmp_password = plan.parameter_value(
role.parameter_prefix + 'SnmpdReadonlyUserPassword')
if (not snmp_password or
previous_snmp_password and
previous_snmp_password != snmp_password):
messages.append({
'text': _(
u"Set your SNMP password for role {0}.").format(role.name),
'is_critical': True,
'link_url': reverse_lazy(
'horizon:infrastructure:parameters:index'),
'link_label': _(u"Configure."),
})
previous_snmp_password = snmp_password
available_flavors = len(api.flavor.Flavor.list(request))
if available_flavors == 0:
messages.append({
'text': _(u"You have no flavors defined."),
'is_critical': True,
'link_url': reverse_lazy('horizon:infrastructure:flavors:index'),
'link_label': _(u"Define flavors."),
})
available_nodes = len(api.node.Node.list(request, associated=False))
if available_nodes == 0:
messages.append({
'text': _(u"You have no nodes available."),
'is_critical': True,
'link_url': reverse_lazy('horizon:infrastructure:nodes:index'),
'link_label': _(u"Register nodes."),
})
elif requested_nodes > available_nodes:
messages.append({
'text': _(u"Not enough registered nodes for this plan. "
u"You need {0} more.").format(
requested_nodes - available_nodes),
'is_critical': True,
'link_url': reverse_lazy('horizon:infrastructure:nodes:index'),
'link_label': _(u"Register more nodes."),
})
# TODO(rdopieralski) Add more checks.
return messages
class EditPlan(horizon.forms.SelfHandlingForm):
def __init__(self, *args, **kwargs):
super(EditPlan, self).__init__(*args, **kwargs)
self.plan = api.tuskar.Plan.get_the_plan(self.request)
self.fields.update(self._role_count_fields(self.plan))
def _role_count_fields(self, plan):
fields = {}
for role in plan.role_list:
field = django.forms.IntegerField(
label=role.name,
widget=tuskar_ui.forms.NumberPickerInput,
initial=plan.get_role_node_count(role),
required=False
)
field.role = role
fields['%s-count' % role.id] = field
return fields
def handle(self, request, data):
parameters = dict(
(field.role.node_count_parameter_name, data[name])
for (name, field) in self.fields.items() if name.endswith('-count')
)
try:
self.plan = self.plan.patch(request, self.plan.uuid, parameters)
except Exception as e:
horizon.exceptions.handle(request, _("Unable to update the plan."))
LOG.exception(e)
return False
return True
class DeployOvercloud(horizon.forms.SelfHandlingForm):
def handle(self, request, data):
try:
plan = api.tuskar.Plan.get_the_plan(request)
except Exception as e:
LOG.exception(e)
horizon.exceptions.handle(request,
_("Unable to deploy overcloud."))
return False
# Auto-generate missing passwords and certificates
if plan.list_generated_parameters():
generated_params = plan.make_generated_parameters()
plan = plan.patch(request, plan.uuid, generated_params)
# Validate plan and create stack
for message in validate_plan(request, plan):
if message['is_critical']:
horizon.messages.success(request, message.text)
return False
try:
stack = api.heat.Stack.get_by_plan(self.request, plan)
if not stack:
api.heat.Stack.create(request,
plan.name,
plan.master_template,
plan.environment,
plan.provider_resource_templates)
except Exception as e:
LOG.exception(e)
horizon.exceptions.handle(
request, _("Unable to deploy overcloud. Reason: {0}").format(
e.error['error']['message']))
return False
else:
msg = _('Deployment in progress.')
horizon.messages.success(request, msg)
return True
class UndeployOvercloud(horizon.forms.SelfHandlingForm):
def handle(self, request, data):
try:
plan = api.tuskar.Plan.get_the_plan(request)
stack = api.heat.Stack.get_by_plan(self.request, plan)
if stack:
api.heat.Stack.delete(request, stack.id)
except Exception as e:
LOG.exception(e)
horizon.exceptions.handle(request,
_("Unable to undeploy overcloud."))
return False
else:
msg = _('Undeployment in progress.')
horizon.messages.success(request, msg)
return True
class PostDeployInit(horizon.forms.SelfHandlingForm):
# TODO(lsmola) put here signed user email, has to be done dynamically
# in init
admin_email = horizon.forms.CharField(
label=_("Admin Email"), initial="example@example.org")
public_host = horizon.forms.CharField(
label=_("Public Host"), initial="", required=False)
region = horizon.forms.CharField(
label=_("Region"), initial="regionOne")
float_allocation_start = horizon.forms.CharField(
label=_("Float Allocation Start"), initial="10.0.0.2")
float_allocation_end = horizon.forms.CharField(
label=_("Float Allocation Start"), initial="10.255.255.254")
float_cidr = horizon.forms.CharField(
label=_("Float CIDR"), initial="10.0.0.0/8")
external_allocation_start = horizon.forms.CharField(
label=_("External Allocation Start"), initial="192.0.2.45")
external_allocation_end = horizon.forms.CharField(
label=_("External Allocation Start"), initial="192.0.2.64")
external_cidr = horizon.forms.CharField(
label=_("External CIDR"), initial="192.0.2.0/24")
def build_endpoints(self, plan, controller_role):
return {
"ceilometer": {
"password": plan.parameter_value(
controller_role.parameter_prefix + 'CeilometerPassword')},
"cinder": {
"password": plan.parameter_value(
controller_role.parameter_prefix + 'CinderPassword')},
"ec2": {
"password": plan.parameter_value(
controller_role.parameter_prefix + 'GlancePassword')},
"glance": {
"password": plan.parameter_value(
controller_role.parameter_prefix + 'GlancePassword')},
"heat": {
"password": plan.parameter_value(
controller_role.parameter_prefix + 'HeatPassword')},
"neutron": {
"password": plan.parameter_value(
controller_role.parameter_prefix + 'NeutronPassword')},
"nova": {
"password": plan.parameter_value(
controller_role.parameter_prefix + 'NovaPassword')},
"novav3": {
"password": plan.parameter_value(
controller_role.parameter_prefix + 'NovaPassword')},
"swift": {
"password": plan.parameter_value(
controller_role.parameter_prefix + 'SwiftPassword'),
'path': '/v1/AUTH_%(tenant_id)s',
'admin_path': '/v1'},
"horizon": {'port': ''}}
def build_neutron_setup(self, data):
# TODO(lsmola) this is default devtest params, this should probably
# go from Tuskar parameters in the future.
return {
"float": {
"name": "default-net",
"allocation_start": data['float_allocation_start'],
"allocation_end": data['float_allocation_end'],
"cidr": data['float_cidr']
},
"external": {
"name": "ext-net",
"allocation_start": data['external_allocation_start'],
"allocation_end": data['external_allocation_end'],
"cidr": data['external_cidr']
}}
def handle(self, request, data):
try:
plan = api.tuskar.Plan.get_the_plan(request)
controller_role = plan.get_role_by_name("controller")
stack = api.heat.Stack.get_by_plan(self.request, plan)
admin_token = plan.parameter_value(
controller_role.parameter_prefix + 'AdminToken')
admin_password = plan.parameter_value(
controller_role.parameter_prefix + 'AdminPassword')
admin_email = data['admin_email']
auth_ip = stack.keystone_ip
auth_url = stack.keystone_auth_url
auth_tenant = 'admin'
auth_user = 'admin'
# do the keystone init
keystone_config.initialize(
auth_ip, admin_token, admin_email, admin_password,
region='regionOne', ssl=None, public=None, user='heat-admin',
pki_setup=False)
# retrieve needed Overcloud clients
keystone_client = clients.get_keystone_client(
auth_user, admin_password, auth_tenant, auth_url)
neutron_client = clients.get_neutron_client(
auth_user, admin_password, auth_tenant, auth_url)
# do the setup endpoints
keystone_config.setup_endpoints(
self.build_endpoints(plan, controller_role),
public_host=data['public_host'],
region=data['region'],
os_auth_url=auth_url,
client=keystone_client)
# do the neutron init
try:
neutron_config.initialize_neutron(
self.build_neutron_setup(data),
neutron_client=neutron_client,
keystone_client=keystone_client)
except neutron_exceptions.BadRequest as e:
LOG.info('Neutron has been already initialized.')
LOG.info(e.message)
except Exception as e:
LOG.exception(e)
horizon.exceptions.handle(request,
_("Unable to initialize Overcloud."))
return False
else:
msg = _('Overcloud has been initialized.')
horizon.messages.success(request, msg)
return True