Designate integration

added designate client;
added SelectDnsDomain step in Cluster Template creation form. This
step is available if we enable dns service. This step contains one
dropdown list of available dns servers.
Domain Name is not required field so if it's not selected then
a cluster will be launched without designate usage.

partial-bp: designate-integration
Change-Id: If3e994026d012b9b33d59c8477d6f2a892f61374
This commit is contained in:
Michael Ionkin 2016-07-13 14:48:16 +03:00 committed by mionkin
parent 09a0530002
commit 1eb34dd38a
11 changed files with 125 additions and 10 deletions

View File

@ -0,0 +1,3 @@
---
features:
- Added integration with Designate for hostname resolution.

View File

@ -9,6 +9,7 @@ Django<1.9,>=1.8 # BSD
django-compressor>=2.0 # MIT
django-openstack-auth>=2.3.0 # Apache-2.0
iso8601>=0.1.11 # MIT
python-designateclient>=1.5.0 # Apache-2.0
python-keystoneclient!=2.1.0,>=2.0.0 # Apache-2.0
python-manilaclient>=1.10.0 # Apache-2.0
python-neutronclient>=4.2.0 # Apache-2.0

View File

@ -0,0 +1,34 @@
# 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 designateclient.v2 import client as designate
from keystoneauth1.identity import generic
from keystoneauth1 import session as keystone_session
from openstack_dashboard.api import base
def client(request):
auth_url = base.url_for(request, 'identity')
token_kwargs = dict(
auth_url=auth_url,
token=request.user.token.id,
tenant_id=request.user.project_id,
tenant_name=request.user.project_name,
)
auth = generic.Token(**token_kwargs)
session = keystone_session.Session(auth=auth)
return designate.Client(session=session)
def get_domain_names(request):
return client(request).zones.list()

View File

@ -233,9 +233,9 @@ def nodegroup_update_acl_rules(request, nid,
def cluster_template_create(request, name, plugin_name, hadoop_version,
description=None, cluster_configs=None,
node_groups=None, anti_affinity=None,
net_id=None, use_autoconfig=None,
shares=None,
is_public=None, is_protected=None):
net_id=None, use_autoconfig=None, shares=None,
is_public=None, is_protected=None,
domain_name=None):
return client(request).cluster_templates.create(
name=name,
plugin_name=plugin_name,
@ -248,7 +248,9 @@ def cluster_template_create(request, name, plugin_name, hadoop_version,
use_autoconfig=use_autoconfig,
shares=shares,
is_public=is_public,
is_protected=is_protected)
is_protected=is_protected,
domain_name=domain_name
)
def cluster_template_list(request, search_opts=None):
@ -268,7 +270,8 @@ def cluster_template_update(request, ct_id, name, plugin_name,
cluster_configs=None, node_groups=None,
anti_affinity=None, net_id=None,
use_autoconfig=None, shares=None,
is_public=None, is_protected=None):
is_public=None, is_protected=None,
domain_name=None):
try:
template = client(request).cluster_templates.update(
cluster_template_id=ct_id,
@ -283,7 +286,8 @@ def cluster_template_update(request, ct_id, name, plugin_name,
use_autoconfig=use_autoconfig,
shares=shares,
is_public=is_public,
is_protected=is_protected
is_protected=is_protected,
domain_name=domain_name
)
except APIException as e:

View File

@ -140,7 +140,8 @@ class DataProcessingClusterTemplateTests(test.TestCase):
use_autoconfig=False,
shares=ct.shares,
is_public=False,
is_protected=False) \
is_protected=False,
domain_name=ct.domain_name) \
.AndReturn(new_ct)
self.mox.ReplayAll()

View File

@ -102,6 +102,10 @@ class CopyClusterTemplate(create_flow.ConfigureClusterTemplate):
fields['is_protected'].initial = (
self.template.is_protected)
elif isinstance(step, create_flow.SelectDnsDomains):
fields = step.action.fields
fields["domain_name"].initial = self.template.domain_name
except Exception:
exceptions.handle(request,
_("Unable to fetch template to copy."))

View File

@ -21,6 +21,7 @@ from horizon import exceptions
from horizon import forms
from horizon import workflows
from sahara_dashboard.api import designate as designateclient
from sahara_dashboard.api import manila as manilaclient
from sahara_dashboard.api import sahara as saharaclient
from sahara_dashboard.content.data_processing.utils import helpers as helpers
@ -275,6 +276,40 @@ class SelectClusterShares(workflows.Step):
return context
class SelectDnsDomainsAction(workflows.Action):
domain_name = forms.DynamicChoiceField(
label=_("Domain Name"),
required=False
)
def __init__(self, request, *args, **kwargs):
super(SelectDnsDomainsAction, self).__init__(request, *args, **kwargs)
def _get_domain_choices(self, request):
domains = designateclient.get_domain_names(request)
choices = [(None, _('No domain is specified'))]
choices.extend(
[(domain.get('name'), domain.get('name')) for domain in domains])
return choices
def populate_domain_name_choices(self, request, context):
return self._get_domain_choices(request)
class Meta(object):
name = _("DNS Domain Names")
help_text_template = (
"cluster_templates/_config_domain_names_help.html")
class SelectDnsDomains(workflows.Step):
action_class = SelectDnsDomainsAction
def contribute(self, data, context):
for k, v in data.items():
context["dns_" + k] = v
return context
class ConfigureClusterTemplate(whelpers.ServiceParametersWorkflow,
whelpers.StatusFormatMixin):
slug = "configure_cluster_template"
@ -303,6 +338,9 @@ class ConfigureClusterTemplate(whelpers.ServiceParametersWorkflow,
if saharaclient.base.is_service_enabled(request, 'share'):
ConfigureClusterTemplate._register_step(self, SelectClusterShares)
if saharaclient.base.is_service_enabled(request, 'dns'):
ConfigureClusterTemplate._register_step(self, SelectDnsDomains)
self._populate_tabs(general_parameters, service_parameters)
super(ConfigureClusterTemplate, self).__init__(request,
@ -353,6 +391,10 @@ class ConfigureClusterTemplate(whelpers.ServiceParametersWorkflow,
if "ct_shares" in context:
ct_shares = context["ct_shares"]
domain = context.get('dns_domain_name', None)
if domain == 'None':
domain = None
# TODO(nkonovalov): Fix client to support default_image_id
saharaclient.cluster_template_create(
request,
@ -366,7 +408,8 @@ class ConfigureClusterTemplate(whelpers.ServiceParametersWorkflow,
use_autoconfig=context['general_use_autoconfig'],
shares=ct_shares,
is_public=context['general_is_public'],
is_protected=context['general_is_protected']
is_protected=context['general_is_protected'],
domain_name=domain
)
hlps = helpers.Helpers(request)

View File

@ -48,6 +48,9 @@ class EditClusterTemplate(copy_flow.CopyClusterTemplate):
fields["cluster_template_id"] = forms.CharField(
widget=forms.HiddenInput(),
initial=self.cluster_template_id)
elif isinstance(step, create_flow.SelectDnsDomains):
fields = step.action.fields
fields["domain_name"].initial = self.template.domain_name
except Exception:
exceptions.handle(request,
_("Unable to fetch template to edit."))
@ -82,6 +85,10 @@ class EditClusterTemplate(copy_flow.CopyClusterTemplate):
if "ct_shares" in context:
ct_shares = context["ct_shares"]
domain = context.get('dns_domain_name', None)
if domain == 'None':
domain = None
saharaclient.cluster_template_update(
request=request,
ct_id=self.cluster_template_id,
@ -95,7 +102,8 @@ class EditClusterTemplate(copy_flow.CopyClusterTemplate):
use_autoconfig=context['general_use_autoconfig'],
shares=ct_shares,
is_public=context['general_is_public'],
is_protected=context['general_is_protected']
is_protected=context['general_is_protected'],
domain_name=domain
)
return True
except exceptions.Conflict as e:

View File

@ -0,0 +1,12 @@
{% load i18n horizon %}
<div class="well">
<p>
{% blocktrans %}Select the domain name for internal and external hostname resolution.{% endblocktrans %}
</p>
<p>
{% blocktrans %}Selected domain name should already exist in the Designate.
You can check it in &quot;DNS&quot; tab on the left menu or by executing {% endblocktrans %}
&quot;designate domain-list&quot;
{% blocktrans %}on the controller node.{% endblocktrans %}
</p>
</div>

View File

@ -22,6 +22,10 @@
<dd>{{ template.is_public|yesno }}</dd>
<dt>{% trans "Protected" %}</dt>
<dd>{{ template.is_protected|yesno }}</dd>
{% if template.domain_name %}
<dt>{% trans "Domain name" %}</dt>
<dd>{{ template.domain_name }}</dd>
{% endif %}
</dl>
<dl class="dl-horizontal">
<dt>{% trans "Anti-affinity enabled for" %}</dt>

View File

@ -215,7 +215,8 @@ def data(TEST):
"shares": [],
"plugin_name": "vanilla",
"tenant_id": "429ad8447c2d47bc8e0382d244e1d1df",
"updated_at": None
"updated_at": None,
"domain_name": None
}
ct1 = cluster_templates.ClusterTemplate(