Use neutronclient for all network operations

Latest novaclient 8.0.0 removed nova-network
related functionality which Sahara depended on for
network operations, even for Neutron.

Now, use neutronclient (and Neutron resources in
Heat) for all network operations.

Additionally, fix devstack coordination backend.

Partially-Implements: bp sahara-remove-nova-network
Closes-Bug: #1692551
Co-Authored-By: Vitaly Gridnev <vgridnev@mirantis.com>
Change-Id: I6b8e12f0d33752e7790c5f40ebe6a3940ff1b0c1
This commit is contained in:
Jeremy Freudberg 2017-05-22 11:32:59 -04:00
parent 8f406bcfb9
commit b4fb2c404c
11 changed files with 81 additions and 77 deletions

View File

@ -1,6 +1,9 @@
# This file contains runtime (non-python) dependencies
# More info at: http://docs.openstack.org/infra/bindep/readme.html
libssl-dev [platform:dpkg]
openssl-devel [platform:rpm]
# Define the basic (test) requirements extracted from bindata-fallback.txt
# - mysqladmin and psql
mariadb [platform:rpm]

View File

@ -185,7 +185,9 @@ function configure_sahara {
# Enable distributed periodic tasks
iniset $SAHARA_CONF_FILE DEFAULT periodic_coordinator_backend_url\
$SAHARA_PERIODIC_COORDINATOR_URL
pip_install tooz[zookeeper]
pip_install tooz[memcached]
restart_service memcached
fi
recreate_database sahara

View File

@ -34,7 +34,7 @@ SAHARA_BIN_DIR=$(get_python_exec_prefix)
SAHARA_ENABLE_DISTRIBUTED_PERIODICS=${SAHARA_ENABLE_DISTRIBUTED_PERIODICS:-\
True}
SAHARA_PERIODIC_COORDINATOR_URL=${SAHARA_PERIODIC_COORDINATOR_URL:-\
kazoo://127.0.0.1:2181}
memcached://127.0.0.1:11211}
#Toggle for deploying Sahara API with Apache + mod_wsgi
SAHARA_USE_MOD_WSGI=${SAHARA_USE_MOD_WSGI:-False}
@ -44,7 +44,3 @@ TEMPEST_SERVICES+=,sahara
enable_service sahara-api sahara-eng
enable_service heat h-eng h-api h-api-cfn h-api-cw
if [ "$SAHARA_ENABLE_DISTRIBUTED_PERIODICS" == "True" ]; then
enable_service zookeeper
fi

View File

@ -0,0 +1,8 @@
---
issues:
- Ironic integration might be broken if floating IPs are used, due to the
use of pre-created ports by the Sahara engine. The status of Ironic
support was untested for this release.
deprecations:
- Support for nova-network is removed, reflective of its removal from nova
itself and from python-novaclient. use_neutron=False is unsupported.

View File

@ -272,15 +272,10 @@ sed '/^Defaults requiretty*/ s/^/#/' -i /etc/sudoers\n
server_groups_old[0].id)
def _shutdown_instance(self, instance):
# tmckay-fp perfect, already testing the right thing
# Heat dissociates and deletes upon deletion of resources
# See OS::Neutron::FloatingIP and OS::Neutron::FloatingIPAssociation
if instance.node_group.floating_ip_pool:
try:
b.execute_with_retries(networks.delete_floating_ip,
instance.instance_id)
except nova_exceptions.NotFound:
LOG.warning("Attempted to delete non-existent floating IP "
"in pool {pool} from instance"
.format(pool=instance.node_group.floating_ip_pool))
pass
try:
volumes.detach_from_instance(instance)

View File

@ -454,21 +454,25 @@ class ClusterStack(object):
properties = {}
inst_name = _get_inst_name(ng)
if ng.floating_ip_pool:
resources.update(self._serialize_nova_floating(ng))
if CONF.use_neutron:
properties["networks"] = [{
"network": self.cluster.neutron_management_network}]
private_net = self.cluster.neutron_management_network
if ng.security_groups or ng.auto_security_group:
properties["security_groups"] = self._get_security_groups(ng)
sec_groups = self._get_security_groups(ng)
# Check if cluster contains user key-pair and include it to template.
if self.cluster.user_keypair_id:
properties["key_name"] = self.cluster.user_keypair_id
port_name = _get_port_name(ng)
resources.update(self._serialize_port(
port_name, private_net, sec_groups))
properties["networks"] = [{"port": {"get_resource": "port"}}]
if ng.floating_ip_pool:
resources.update(self._serialize_neutron_floating(ng))
gen_userdata_func = self.node_groups_extra[ng.id]['gen_userdata_func']
key_script = gen_userdata_func(ng, inst_name)
if CONF.heat_enable_wait_condition:
@ -537,23 +541,33 @@ class ClusterStack(object):
}
}
def _serialize_nova_floating(self, ng):
def _serialize_neutron_floating(self, ng):
return {
"floating_ip": {
"type": "OS::Nova::FloatingIP",
"type": "OS::Neutron::FloatingIP",
"properties": {
"pool": ng.floating_ip_pool
}
},
"floating_ip_assoc": {
"type": "OS::Nova::FloatingIPAssociation",
"properties": {
"floating_ip": {"get_resource": "floating_ip"},
"server_id": {"get_resource": INSTANCE_RESOURCE_NAME}
"floating_network_id": ng.floating_ip_pool,
"port_id": {"get_resource": "port"}
}
}
}
def _serialize_port(self, port_name, fixed_net_id, security_groups):
properties = {
"network_id": fixed_net_id,
"replacement_policy": "AUTO",
"name": port_name
}
if security_groups:
properties["security_groups"] = security_groups
return {
"port": {
"type": "OS::Neutron::Port",
"properties": properties,
}
}
def _serialize_volume(self, ng):
if not ng.volumes_size or not ng.volumes_per_node:
return {}

View File

@ -18,7 +18,6 @@ import six
from sahara import conductor as c
from sahara import context
from sahara.utils.openstack import base as b
from sahara.utils.openstack import nova
conductor = c.API
@ -65,16 +64,3 @@ def init_instances_ips(instance):
"internal_ip": internal_ip})
return internal_ip and management_ip
def assign_floating_ip(instance_id, pool):
ip = b.execute_with_retries(nova.client().floating_ips.create, pool)
server = b.execute_with_retries(nova.client().servers.get, instance_id)
b.execute_with_retries(server.add_floating_ip, ip)
def delete_floating_ip(instance_id):
fl_ips = b.execute_with_retries(
nova.client().floating_ips.findall, instance_id=instance_id)
for fl_ip in fl_ips:
b.execute_with_retries(nova.client().floating_ips.delete, fl_ip.id)

View File

@ -28,6 +28,7 @@ from sahara.service.api import v10 as api
from sahara.utils import general as g
import sahara.utils.openstack.cinder as cinder
from sahara.utils.openstack import images as sahara_images
import sahara.utils.openstack.neutron as neutron
import sahara.utils.openstack.nova as nova
@ -181,11 +182,11 @@ def check_flavor_exists(flavor_id):
def check_security_groups_exist(security_groups):
security_group_list = nova.client().security_groups.list()
security_group_list = neutron.client().list_security_groups()
allowed_groups = set()
for sg in security_group_list:
allowed_groups.add(six.text_type(sg.id))
allowed_groups.add(sg.name)
for sg in security_group_list['security_groups']:
allowed_groups.add(sg['name'])
allowed_groups.add(sg['id'])
for sg in security_groups:
if sg not in allowed_groups:
@ -196,7 +197,7 @@ def check_security_groups_exist(security_groups):
def check_floatingip_pool_exists(ng_name, pool_id):
network = None
if CONF.use_neutron:
network = nova.get_network(id=pool_id)
network = neutron.get_network(pool_id)
else:
# tmckay-fp, whoa, this suggests that we allow floating_ip_pools with
# nova? Can that be true? Scour for this
@ -292,7 +293,7 @@ def check_keypair_exists(keypair):
def check_network_exists(net_id):
if not nova.get_network(id=net_id):
if not neutron.get_network(net_id):
raise ex.NotFoundException(net_id, _("Network %s not found"))

View File

@ -17,6 +17,7 @@ import ast
import re
import mock
from neutronclient.common import exceptions as neutron_ex
import novaclient.exceptions as nova_ex
import six
@ -62,10 +63,9 @@ def _get_keypair(name):
raise nova_ex.NotFound("")
def _get_network(**kwargs):
if 'id' in kwargs and (
kwargs['id'] != "d9a3bebc-f788-4b81-9a93-aa048022c1ca"):
raise nova_ex.NotFound("")
def _get_network(resource, id):
if id != "d9a3bebc-f788-4b81-9a93-aa048022c1ca":
raise neutron_ex.NotFound("")
return 'OK'
@ -104,20 +104,15 @@ class FakeFlavor(object):
self.id = id
class FakeSecurityGroup(object):
def __init__(self, id, name):
self.id = id
self.name = name
def _get_flavors_list():
return [FakeFlavor("42")]
def _get_security_groups_list():
return [FakeSecurityGroup("1", "default"),
FakeSecurityGroup("2", "group1"),
FakeSecurityGroup("3", "group2")]
return {'security_groups': [
{"id": "1", "name": "default"},
{"id": "2", "name": "group1"},
{"id": "3", "name": "group2"}]}
def start_patch(patch_templates=True):
@ -158,13 +153,16 @@ def start_patch(patch_templates=True):
get_cl_templates.return_value = []
nova().flavors.list.side_effect = _get_flavors_list
nova().security_groups.list.side_effect = _get_security_groups_list
nova().keypairs.get.side_effect = _get_keypair
nova().networks.find.side_effect = _get_network
nova().networks.find.__name__ = 'find'
nova().floating_ip_pools.list.side_effect = _get_fl_ip_pool_list
nova().availability_zones.list.side_effect = _get_availability_zone_list
neutron_p = mock.patch("sahara.utils.openstack.neutron.client")
neutron = neutron_p.start()
neutron().find_resource_by_id.side_effect = _get_network
neutron().find_resource_by_id.__name__ = 'find_resource_by_id'
neutron().list_security_groups.side_effect = _get_security_groups_list
heat = heat_p.start()
heat().stacks.list.side_effect = _get_heat_stack_list
@ -235,7 +233,7 @@ def start_patch(patch_templates=True):
# request data to validate
patchers = [get_clusters_p, get_cluster_p,
nova_p, get_image_p, heat_p, image_manager_p, cinder_p,
cinder_exists_p]
cinder_exists_p, neutron_p]
if patch_templates:
patchers.extend([get_ng_template_p, get_ng_templates_p,
get_cl_template_p, get_cl_templates_p])

View File

@ -14,6 +14,7 @@
# limitations under the License.
from neutronclient.common import exceptions as n_ex
from neutronclient.neutron import client as neutron_cli
from oslo_config import cfg
from oslo_log import log as logging
@ -104,3 +105,11 @@ def get_private_network_cidrs(cluster):
cidrs.append(subnet['subnet']['cidr'])
return cidrs
def get_network(id):
try:
return base.execute_with_retries(
client().find_resource_by_id, 'network', id)
except n_ex.NotFound:
return None

View File

@ -14,7 +14,6 @@
# limitations under the License.
from novaclient import client as nova_client
from novaclient import exceptions as nova_ex
from oslo_config import cfg
from sahara.service import sessions
@ -57,10 +56,3 @@ def get_flavor(**kwargs):
def get_instance_info(instance):
return base.execute_with_retries(
client().servers.get, instance.instance_id)
def get_network(**kwargs):
try:
return base.execute_with_retries(client().networks.find, **kwargs)
except nova_ex.NotFound:
return None