New VIP-related fields in the database
* Add 'is_user_defined' field to 'ip_addrs' table. * Rename 'vip_type' field to 'vip_name' of table 'ip_addrs'. * Add 'vip_namespace' field to 'ip_addrs' table. * Copy vip namespaces from plugin table network roles to 'vip_namespace' field according to the unique vip name. * Add database migrations. * Add unit test for migrations. Change-Id: Ia3e1d7f6e08dbebcb182de75eeaf58ddf6be4a8d Partial-bug: #1482399
This commit is contained in:
parent
b2a2d0799c
commit
169fae21b0
|
@ -164,11 +164,15 @@ NETWORK_INTERFACE_TYPES = Enum(
|
|||
'bond'
|
||||
)
|
||||
|
||||
NETWORK_VIP_TYPES = Enum(
|
||||
NETWORK_VIP_NAMES_V6_1 = Enum(
|
||||
'haproxy',
|
||||
'vrouter',
|
||||
)
|
||||
|
||||
VIP_NAME_MAX_LEN = 25
|
||||
VIP_NAMESPACE_MAX_LEN = 25
|
||||
NETWORK_GROUP_NAME_MAX_LEN = 50
|
||||
|
||||
BOND_MODES = Enum(
|
||||
# same for both OVS and linux
|
||||
'active-backup',
|
||||
|
|
|
@ -20,20 +20,25 @@ Create Date: 2015-12-15 17:20:49.519542
|
|||
|
||||
"""
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
from oslo_serialization import jsonutils
|
||||
|
||||
revision = '11a9adc6d36a'
|
||||
down_revision = '43b2cb64dae6'
|
||||
|
||||
from alembic import op # noqa
|
||||
import sqlalchemy as sa # noqa
|
||||
|
||||
|
||||
def upgrade():
|
||||
add_foreign_key_ondelete()
|
||||
upgrade_ip_address()
|
||||
update_vips_from_network_roles()
|
||||
|
||||
|
||||
def downgrade():
|
||||
remove_foreign_key_ondelete()
|
||||
downgrade_ip_address()
|
||||
|
||||
|
||||
def remove_foreign_key_ondelete():
|
||||
|
@ -419,3 +424,114 @@ def add_foreign_key_ondelete():
|
|||
['parent_id'], ['id'],
|
||||
ondelete='CASCADE'
|
||||
)
|
||||
|
||||
|
||||
def upgrade_ip_address():
|
||||
|
||||
op.add_column(
|
||||
'ip_addrs',
|
||||
sa.Column(
|
||||
'is_user_defined',
|
||||
sa.Boolean,
|
||||
nullable=False,
|
||||
default=False,
|
||||
server_default="false"
|
||||
)
|
||||
)
|
||||
|
||||
op.add_column(
|
||||
'ip_addrs',
|
||||
sa.Column(
|
||||
'vip_namespace',
|
||||
sa.String(length=25),
|
||||
nullable=True,
|
||||
default=None,
|
||||
server_default=None
|
||||
)
|
||||
)
|
||||
|
||||
op.alter_column(
|
||||
'ip_addrs',
|
||||
'vip_type',
|
||||
new_column_name='vip_name',
|
||||
type_=sa.String(length=25)
|
||||
)
|
||||
|
||||
|
||||
def update_vips_from_network_roles():
|
||||
|
||||
def _update_network_roles_from_db_metadata(query):
|
||||
connection = op.get_bind()
|
||||
_vip_name_to_vip_data = {}
|
||||
|
||||
select = sa.text(query)
|
||||
network_roles_metadata = connection.execute(select)
|
||||
for network_roles_json in network_roles_metadata:
|
||||
if not network_roles_json or not network_roles_json[0]:
|
||||
continue
|
||||
network_roles = jsonutils.loads(network_roles_json[0])
|
||||
# warning: in current schema it is possible that network
|
||||
# role is declared as dict
|
||||
if isinstance(network_roles, dict):
|
||||
network_roles = [network_roles]
|
||||
for network_role in network_roles:
|
||||
vips = network_role.get('properties', {}).get('vip', [])
|
||||
for vip in vips:
|
||||
_vip_name_to_vip_data[vip['name']] = vip
|
||||
return _vip_name_to_vip_data
|
||||
|
||||
roles_vip_name_to_vip_data = {}
|
||||
|
||||
# get namespaces from plugins
|
||||
roles_vip_name_to_vip_data.update(
|
||||
_update_network_roles_from_db_metadata(
|
||||
"SELECT network_roles_metadata from plugins"
|
||||
)
|
||||
)
|
||||
|
||||
# get namespaces from releases
|
||||
roles_vip_name_to_vip_data.update(
|
||||
_update_network_roles_from_db_metadata(
|
||||
"SELECT network_roles_metadata from releases"
|
||||
)
|
||||
)
|
||||
|
||||
# perform update
|
||||
connection = op.get_bind()
|
||||
ip_addrs_select = sa.text(
|
||||
"SELECT id, vip_name from ip_addrs"
|
||||
)
|
||||
ip_addrs = connection.execute(ip_addrs_select)
|
||||
|
||||
ip_addrs_update = sa.sql.text(
|
||||
"UPDATE ip_addrs "
|
||||
"SET vip_namespace = :vip_namespace WHERE id = :id"
|
||||
)
|
||||
|
||||
existing_names_to_id = dict(
|
||||
(vip_name, vip_id) for (vip_id, vip_name) in ip_addrs
|
||||
)
|
||||
|
||||
for vip_name in existing_names_to_id:
|
||||
|
||||
namespace = roles_vip_name_to_vip_data\
|
||||
.get(vip_name, {}).get('namespace')
|
||||
|
||||
# update only if namespace arrived
|
||||
if namespace:
|
||||
connection.execute(
|
||||
ip_addrs_update,
|
||||
id=existing_names_to_id[vip_name],
|
||||
vip_namespace=namespace
|
||||
)
|
||||
|
||||
|
||||
def downgrade_ip_address():
|
||||
op.alter_column(
|
||||
'ip_addrs',
|
||||
'vip_name',
|
||||
new_column_name='vip_type',
|
||||
type_=sa.String(length=25)
|
||||
)
|
||||
op.drop_column('ip_addrs', 'is_user_defined')
|
||||
op.drop_column('ip_addrs', 'vip_namespace')
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
# 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 sqlalchemy import Boolean
|
||||
from sqlalchemy import Column
|
||||
from sqlalchemy.dialects import postgresql as psql
|
||||
from sqlalchemy.ext.mutable import MutableDict
|
||||
|
@ -22,6 +22,7 @@ from sqlalchemy import Integer
|
|||
from sqlalchemy.orm import relationship
|
||||
from sqlalchemy import String
|
||||
|
||||
from nailgun import consts
|
||||
from nailgun.db.sqlalchemy.models.base import Base
|
||||
from nailgun.db.sqlalchemy.models.fields import JSON
|
||||
|
||||
|
@ -33,8 +34,18 @@ class IPAddr(Base):
|
|||
ondelete="CASCADE"))
|
||||
node = Column(Integer, ForeignKey('nodes.id', ondelete="CASCADE"))
|
||||
ip_addr = Column(psql.INET, nullable=False)
|
||||
vip_type = Column(String(25), nullable=True)
|
||||
|
||||
vip_name = Column(String(consts.VIP_NAME_MAX_LEN), nullable=True)
|
||||
vip_namespace = Column(
|
||||
String(consts.VIP_NAMESPACE_MAX_LEN),
|
||||
nullable=True,
|
||||
server_default=None
|
||||
)
|
||||
is_user_defined = Column(
|
||||
Boolean,
|
||||
nullable=False,
|
||||
default=False,
|
||||
server_default="false"
|
||||
)
|
||||
network_data = relationship("NetworkGroup")
|
||||
node_data = relationship("Node")
|
||||
|
||||
|
@ -52,7 +63,7 @@ class NetworkGroup(Base):
|
|||
__tablename__ = 'network_groups'
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
name = Column(String(50), nullable=False)
|
||||
name = Column(String(consts.NETWORK_GROUP_NAME_MAX_LEN), nullable=False)
|
||||
# can be nullable only for fuelweb admin net
|
||||
release = Column(Integer, ForeignKey('releases.id', ondelete='CASCADE'))
|
||||
# can be nullable only for fuelweb admin net
|
||||
|
|
|
@ -135,11 +135,11 @@ class UpgradeHelper(object):
|
|||
renamed_vips = collections.defaultdict(dict)
|
||||
for ng_name, vips in six.iteritems(vips):
|
||||
ng_vip_rules = rename_vip_rules[ng_name]
|
||||
for vip_type, vip_addr in six.iteritems(vips):
|
||||
if vip_type not in ng_vip_rules:
|
||||
for vip_name, vip_addr in six.iteritems(vips):
|
||||
if vip_name not in ng_vip_rules:
|
||||
continue
|
||||
new_vip_type = ng_vip_rules[vip_type]
|
||||
renamed_vips[ng_name][new_vip_type] = vip_addr
|
||||
new_vip_name = ng_vip_rules[vip_name]
|
||||
renamed_vips[ng_name][new_vip_name] = vip_addr
|
||||
return renamed_vips
|
||||
|
||||
@classmethod
|
||||
|
@ -159,7 +159,7 @@ class UpgradeHelper(object):
|
|||
consts.NETWORKS.management):
|
||||
vips.pop(ng_name)
|
||||
# NOTE(akscram): In the 7.0 release was introduced networking
|
||||
# templates that use the vip_type column as
|
||||
# templates that use the vip_name column as
|
||||
# unique names of VIPs.
|
||||
if version.LooseVersion(orig_cluster.release.environment_version) < \
|
||||
version.LooseVersion("7.0"):
|
||||
|
|
|
@ -301,12 +301,12 @@ class NetworkManager(object):
|
|||
db().flush()
|
||||
|
||||
@classmethod
|
||||
def get_assigned_vip(cls, nodegroup, network_name, vip_type):
|
||||
def get_assigned_vip(cls, nodegroup, network_name, vip_name):
|
||||
"""Get VIP address, if it was assigned already
|
||||
|
||||
:param nodegroup: Name of the node group.
|
||||
:param nerwork_name: Name of a network the VIP is allocated in.
|
||||
:param vip_type: Type of a required VIP.
|
||||
:param vip_name: Type of a required VIP.
|
||||
:returns: IP address of a VIP that matches specified criterias.
|
||||
None, if no VIP matches specificied criterias.
|
||||
|
||||
|
@ -314,7 +314,7 @@ class NetworkManager(object):
|
|||
network = cls.get_network_by_name_and_nodegroup(network_name,
|
||||
nodegroup)
|
||||
|
||||
cluster_vip_q = db().query(IPAddr).filter_by(vip_type=vip_type)
|
||||
cluster_vip_q = db().query(IPAddr).filter_by(vip_name=vip_name)
|
||||
|
||||
if network is not None:
|
||||
cluster_vip_q = cluster_vip_q.filter_by(network=network.id)
|
||||
|
@ -325,8 +325,7 @@ class NetworkManager(object):
|
|||
return cluster_vip.ip_addr
|
||||
|
||||
@classmethod
|
||||
def assign_vip(cls, nodegroup, network_name,
|
||||
vip_type=consts.NETWORK_VIP_TYPES.haproxy):
|
||||
def assign_vip(cls, nodegroup, network_name, vip_name):
|
||||
"""Idempotent assignment of VirtualIP addresses to nodegroup.
|
||||
|
||||
Returns VIP for given nodegroup and network.
|
||||
|
@ -342,14 +341,14 @@ class NetworkManager(object):
|
|||
:type nodegroup: NodeGroup model
|
||||
:param network_name: Network name
|
||||
:type network_name: str
|
||||
:param vip_type: Type of VIP
|
||||
:type vip_type: str
|
||||
:param vip_name: Name of VIP
|
||||
:type vip_name: str
|
||||
:returns: assigned VIP (string)
|
||||
:raises: Exception
|
||||
|
||||
"""
|
||||
already_assigned = cls.get_assigned_vip(nodegroup,
|
||||
network_name, vip_type)
|
||||
network_name, vip_name)
|
||||
network = cls.get_network_by_name_and_nodegroup(network_name,
|
||||
nodegroup)
|
||||
|
||||
|
@ -365,7 +364,7 @@ class NetworkManager(object):
|
|||
cluster_vip = db().query(IPAddr).filter_by(
|
||||
network=network.id,
|
||||
node=None,
|
||||
vip_type=vip_type
|
||||
vip_name=vip_name
|
||||
).first()
|
||||
|
||||
ips_in_use = None
|
||||
|
@ -380,7 +379,7 @@ class NetworkManager(object):
|
|||
|
||||
# IP address has not been assigned, let's do it
|
||||
vip = cls.get_free_ips(network, ips_in_use=ips_in_use)[0]
|
||||
ne_db = IPAddr(network=network.id, ip_addr=vip, vip_type=vip_type)
|
||||
ne_db = IPAddr(network=network.id, ip_addr=vip, vip_name=vip_name)
|
||||
|
||||
# delete stalled VIP address after new one was found.
|
||||
if cluster_vip:
|
||||
|
@ -403,14 +402,14 @@ class NetworkManager(object):
|
|||
|
||||
nodegroup = objects.Cluster.get_controllers_node_group(cluster)
|
||||
for ng in cluster.network_groups:
|
||||
for vip_type in ng.meta.get('vips', ()):
|
||||
for vip_name in ng.meta.get('vips', ()):
|
||||
# used for backwards compatibility
|
||||
if vip_type == consts.NETWORK_VIP_TYPES.haproxy:
|
||||
if vip_name == consts.NETWORK_VIP_NAMES_V6_1.haproxy:
|
||||
key = '{0}_vip'.format(ng.name)
|
||||
else:
|
||||
key = '{0}_{1}_vip'.format(ng.name, vip_type)
|
||||
key = '{0}_{1}_vip'.format(ng.name, vip_name)
|
||||
|
||||
result[key] = cls.assign_vip(nodegroup, ng.name, vip_type)
|
||||
result[key] = cls.assign_vip(nodegroup, ng.name, vip_name)
|
||||
|
||||
return result
|
||||
|
||||
|
@ -419,7 +418,7 @@ class NetworkManager(object):
|
|||
node_group_id = objects.Cluster.get_controllers_group_id(cluster)
|
||||
cluster_vips = db.query(IPAddr).join(IPAddr.network_data).filter(
|
||||
IPAddr.node.is_(None) &
|
||||
IPAddr.vip_type.isnot(None) &
|
||||
IPAddr.vip_name.isnot(None) &
|
||||
(NetworkGroup.group_id == node_group_id)
|
||||
)
|
||||
return cluster_vips
|
||||
|
@ -435,7 +434,7 @@ class NetworkManager(object):
|
|||
cluster_vips = cls._get_assigned_vips_for_net_groups(cluster)
|
||||
vips = defaultdict(dict)
|
||||
for vip in cluster_vips:
|
||||
vips[vip.network_data.name][vip.vip_type] = vip.ip_addr
|
||||
vips[vip.network_data.name][vip.vip_name] = vip.ip_addr
|
||||
return vips
|
||||
|
||||
@classmethod
|
||||
|
@ -455,12 +454,12 @@ class NetworkManager(object):
|
|||
cluster_vips = cls._get_assigned_vips_for_net_groups(cluster)
|
||||
assigned_vips = defaultdict(dict)
|
||||
for vip in cluster_vips:
|
||||
assigned_vips[vip.network_data.name][vip.vip_type] = vip
|
||||
assigned_vips[vip.network_data.name][vip.vip_name] = vip
|
||||
for net_group in cluster.network_groups:
|
||||
if net_group.name not in vips:
|
||||
continue
|
||||
assigned_vips_by_type = assigned_vips.get(net_group.name, {})
|
||||
for vip_type, ip_addr in six.iteritems(vips[net_group.name]):
|
||||
for vip_name, ip_addr in six.iteritems(vips[net_group.name]):
|
||||
if not cls.check_ip_belongs_to_net(ip_addr, net_group):
|
||||
ranges = [(rng.first, rng.last)
|
||||
for rng in net_group.ip_ranges]
|
||||
|
@ -470,14 +469,14 @@ class NetworkManager(object):
|
|||
"ranges {3} of the cluster \"{4}\"."
|
||||
.format(ip_addr, net_group.id, net_group.name, ranges,
|
||||
cluster.id))
|
||||
if vip_type in assigned_vips_by_type:
|
||||
assigned_vip = assigned_vips_by_type[vip_type]
|
||||
if vip_name in assigned_vips_by_type:
|
||||
assigned_vip = assigned_vips_by_type[vip_name]
|
||||
assigned_vip.ip_addr = ip_addr
|
||||
else:
|
||||
vip = IPAddr(
|
||||
network=net_group.id,
|
||||
ip_addr=ip_addr,
|
||||
vip_type=vip_type,
|
||||
vip_name=vip_name,
|
||||
)
|
||||
db().add(vip)
|
||||
db().flush()
|
||||
|
@ -1708,7 +1707,7 @@ class NetworkManager(object):
|
|||
x[0] for x in
|
||||
db().query(IPAddr.ip_addr).filter(
|
||||
IPAddr.network == network_id,
|
||||
or_(IPAddr.node.isnot(None), IPAddr.vip_type.isnot(None))
|
||||
or_(IPAddr.node.isnot(None), IPAddr.vip_name.isnot(None))
|
||||
)
|
||||
]
|
||||
|
||||
|
@ -1806,7 +1805,7 @@ class AllocateVIPs70Mixin(object):
|
|||
cluster_db, node_group.name)
|
||||
net_group = cls.get_network_group_for_role(
|
||||
net_role, net_group_mapping)
|
||||
return cls.assign_vip(node_group, net_group, vip_type='public')
|
||||
return cls.assign_vip(node_group, net_group, vip_name='public')
|
||||
|
||||
@classmethod
|
||||
def _assign_vips_for_net_groups(cls, cluster):
|
||||
|
|
|
@ -716,11 +716,19 @@ class TestNovaNetworkConfigurationHandlerHA(BaseIntegrationTest):
|
|||
|
||||
self.assertEqual(
|
||||
resp['management_vip'],
|
||||
self.net_manager.assign_vip(nodegroup, 'management'))
|
||||
self.net_manager.assign_vip(
|
||||
nodegroup,
|
||||
'management',
|
||||
consts.NETWORK_VIP_NAMES_V6_1.haproxy
|
||||
))
|
||||
|
||||
self.assertEqual(
|
||||
resp['public_vip'],
|
||||
self.net_manager.assign_vip(nodegroup, 'public'))
|
||||
self.net_manager.assign_vip(
|
||||
nodegroup,
|
||||
'public',
|
||||
consts.NETWORK_VIP_NAMES_V6_1.haproxy
|
||||
))
|
||||
|
||||
|
||||
class TestAdminNetworkConfiguration(BaseIntegrationTest):
|
||||
|
|
|
@ -55,12 +55,12 @@ class BaseNetworkManagerTest(BaseIntegrationTest):
|
|||
for net_group in cluster.network_groups:
|
||||
if net_group.name not in rules:
|
||||
continue
|
||||
vips_by_types = rules[net_group.name]
|
||||
for vip_type, ip_addr in vips_by_types.items():
|
||||
vips_by_names = rules[net_group.name]
|
||||
for vip_name, ip_addr in vips_by_names.items():
|
||||
ip = IPAddr(
|
||||
network=net_group.id,
|
||||
ip_addr=ip_addr,
|
||||
vip_type=vip_type,
|
||||
vip_name=vip_name,
|
||||
)
|
||||
self.db.add(ip)
|
||||
created_ips.append(ip)
|
||||
|
@ -195,9 +195,15 @@ class TestNetworkManager(BaseNetworkManagerTest):
|
|||
self.env.clusters[0])
|
||||
|
||||
vip = self.env.network_manager.assign_vip(
|
||||
nodegroup, consts.NETWORKS.management)
|
||||
nodegroup,
|
||||
consts.NETWORKS.management,
|
||||
consts.NETWORK_VIP_NAMES_V6_1.haproxy
|
||||
)
|
||||
vip2 = self.env.network_manager.assign_vip(
|
||||
nodegroup, consts.NETWORKS.management)
|
||||
nodegroup,
|
||||
consts.NETWORKS.management,
|
||||
consts.NETWORK_VIP_NAMES_V6_1.haproxy
|
||||
)
|
||||
|
||||
self.assertEqual(vip, vip2)
|
||||
|
||||
|
@ -206,8 +212,10 @@ class TestNetworkManager(BaseNetworkManagerTest):
|
|||
nodegroup = objects.Cluster.get_controllers_node_group(
|
||||
self.env.clusters[0])
|
||||
|
||||
self.env.network_manager.assign_vip(nodegroup,
|
||||
consts.NETWORKS.fuelweb_admin)
|
||||
self.env.network_manager.assign_vip(
|
||||
nodegroup,
|
||||
consts.NETWORKS.fuelweb_admin,
|
||||
consts.NETWORK_VIP_NAMES_V6_1.haproxy)
|
||||
|
||||
def test_assign_vip_throws_not_found_exception(self):
|
||||
self.env.create_cluster(api=True)
|
||||
|
@ -219,7 +227,9 @@ class TestNetworkManager(BaseNetworkManagerTest):
|
|||
"Network 'non-existing-network' for nodegroup='[\w-]+' not found.",
|
||||
self.env.network_manager.assign_vip,
|
||||
nodegroup,
|
||||
'non-existing-network')
|
||||
'non-existing-network',
|
||||
consts.NETWORK_VIP_NAMES_V6_1.haproxy
|
||||
)
|
||||
|
||||
def test_vip_for_admin_network_is_free(self):
|
||||
admin_net_id = self.env.network_manager.get_admin_network_group_id()
|
||||
|
@ -252,7 +262,8 @@ class TestNetworkManager(BaseNetworkManagerTest):
|
|||
self.env.network_manager.assign_admin_ips(cluster.nodes)
|
||||
admin_vip = self.env.network_manager.assign_vip(
|
||||
objects.Cluster.get_controllers_node_group(cluster),
|
||||
consts.NETWORKS.fuelweb_admin
|
||||
consts.NETWORKS.fuelweb_admin,
|
||||
consts.NETWORK_VIP_NAMES_V6_1.haproxy
|
||||
)
|
||||
|
||||
node_ips = [n.ip for n in self.env.nodes]
|
||||
|
@ -548,12 +559,12 @@ class TestNetworkManager(BaseNetworkManagerTest):
|
|||
def test_get_assigned_vips(self):
|
||||
vips_to_create = {
|
||||
consts.NETWORKS.management: {
|
||||
consts.NETWORK_VIP_TYPES.haproxy: '192.168.0.1',
|
||||
consts.NETWORK_VIP_TYPES.vrouter: '192.168.0.2',
|
||||
consts.NETWORK_VIP_NAMES_V6_1.haproxy: '192.168.0.1',
|
||||
consts.NETWORK_VIP_NAMES_V6_1.vrouter: '192.168.0.2',
|
||||
},
|
||||
consts.NETWORKS.public: {
|
||||
consts.NETWORK_VIP_TYPES.haproxy: '172.16.0.2',
|
||||
consts.NETWORK_VIP_TYPES.vrouter: '172.16.0.3',
|
||||
consts.NETWORK_VIP_NAMES_V6_1.haproxy: '172.16.0.2',
|
||||
consts.NETWORK_VIP_NAMES_V6_1.vrouter: '172.16.0.3',
|
||||
},
|
||||
}
|
||||
cluster = self.env.create_cluster(api=False)
|
||||
|
@ -564,20 +575,20 @@ class TestNetworkManager(BaseNetworkManagerTest):
|
|||
def test_assign_given_vips_for_net_groups(self):
|
||||
vips_to_create = {
|
||||
consts.NETWORKS.management: {
|
||||
consts.NETWORK_VIP_TYPES.haproxy: '192.168.0.1',
|
||||
consts.NETWORK_VIP_NAMES_V6_1.haproxy: '192.168.0.1',
|
||||
},
|
||||
consts.NETWORKS.public: {
|
||||
consts.NETWORK_VIP_TYPES.haproxy: '172.16.0.2',
|
||||
consts.NETWORK_VIP_NAMES_V6_1.haproxy: '172.16.0.2',
|
||||
},
|
||||
}
|
||||
vips_to_assign = {
|
||||
consts.NETWORKS.management: {
|
||||
consts.NETWORK_VIP_TYPES.haproxy: '192.168.0.1',
|
||||
consts.NETWORK_VIP_TYPES.vrouter: '192.168.0.2',
|
||||
consts.NETWORK_VIP_NAMES_V6_1.haproxy: '192.168.0.1',
|
||||
consts.NETWORK_VIP_NAMES_V6_1.vrouter: '192.168.0.2',
|
||||
},
|
||||
consts.NETWORKS.public: {
|
||||
consts.NETWORK_VIP_TYPES.haproxy: '172.16.0.4',
|
||||
consts.NETWORK_VIP_TYPES.vrouter: '172.16.0.5',
|
||||
consts.NETWORK_VIP_NAMES_V6_1.haproxy: '172.16.0.4',
|
||||
consts.NETWORK_VIP_NAMES_V6_1.vrouter: '172.16.0.5',
|
||||
},
|
||||
}
|
||||
cluster = self.env.create_cluster(api=False)
|
||||
|
@ -600,7 +611,7 @@ class TestNetworkManager(BaseNetworkManagerTest):
|
|||
def test_assign_given_vips_for_net_groups_assign_error(self):
|
||||
vips_to_assign = {
|
||||
consts.NETWORKS.management: {
|
||||
consts.NETWORK_VIP_TYPES.haproxy: '10.10.0.1',
|
||||
consts.NETWORK_VIP_NAMES_V6_1.haproxy: '10.10.0.1',
|
||||
},
|
||||
}
|
||||
expected_msg_regexp = '^Cannot assign VIP with the address "10.10.0.1"'
|
||||
|
@ -1155,7 +1166,7 @@ class TestNeutronManager70(BaseNetworkManagerTest):
|
|||
endpoint_ip = self.net_manager.get_end_point_ip(self.cluster.id)
|
||||
assign_vip_mock.assert_called_once_with(
|
||||
objects.Cluster.get_controllers_node_group(self.cluster),
|
||||
mock.ANY, vip_type='public')
|
||||
mock.ANY, vip_name='public')
|
||||
self.assertEqual(endpoint_ip, vip)
|
||||
|
||||
def test_assign_vips_for_net_groups_for_api(self):
|
||||
|
@ -1276,7 +1287,7 @@ class TestNovaNetworkManager70(TestNeutronManager70):
|
|||
endpoint_ip = self.net_manager.get_end_point_ip(self.cluster.id)
|
||||
assign_vip_mock.assert_called_once_with(
|
||||
objects.Cluster.get_controllers_node_group(self.cluster),
|
||||
mock.ANY, vip_type='public')
|
||||
mock.ANY, vip_name='public')
|
||||
self.assertEqual(endpoint_ip, vip)
|
||||
|
||||
|
||||
|
|
|
@ -23,8 +23,6 @@ from nailgun.test import base
|
|||
class TestDbMigrations(base.BaseTestCase):
|
||||
|
||||
def test_clean_downgrade(self):
|
||||
# We don't have data migration for clusters with vip_type 'ovs'
|
||||
# so checking migration only for clean DB
|
||||
dropdb()
|
||||
alembic.command.upgrade(ALEMBIC_CONFIG, 'head')
|
||||
alembic.command.downgrade(ALEMBIC_CONFIG, 'base')
|
||||
|
|
|
@ -145,7 +145,7 @@ class TestVipTypesMigration(base.BaseAlembicMigrationTest):
|
|||
sa.select([ip_addrs_table.c.vip_type]).where(
|
||||
ip_addrs_table.c.ip_addr == '192.168.0.2')
|
||||
).first()
|
||||
self.assertEqual(ip_addr[0], consts.NETWORK_VIP_TYPES.haproxy)
|
||||
self.assertEqual(ip_addr[0], consts.NETWORK_VIP_NAMES_V6_1.haproxy)
|
||||
|
||||
def test_vip_type_in_releases(self):
|
||||
releases_table = self.meta.tables['releases']
|
||||
|
@ -158,7 +158,7 @@ class TestVipTypesMigration(base.BaseAlembicMigrationTest):
|
|||
neutron = networks_meta['neutron']['networks'][0]
|
||||
self.assertItemsEqual(
|
||||
neutron.get('vips'),
|
||||
[consts.NETWORK_VIP_TYPES.haproxy])
|
||||
[consts.NETWORK_VIP_NAMES_V6_1.haproxy])
|
||||
|
||||
nova_network = networks_meta['nova_network']['networks'][0]
|
||||
self.assertIsNone(nova_network.get('vips'))
|
||||
|
@ -171,7 +171,7 @@ class TestVipTypesMigration(base.BaseAlembicMigrationTest):
|
|||
).first()[0]
|
||||
|
||||
vips = jsonutils.loads(meta).get('vips')
|
||||
self.assertEqual(vips, [consts.NETWORK_VIP_TYPES.haproxy])
|
||||
self.assertEqual(vips, [consts.NETWORK_VIP_NAMES_V6_1.haproxy])
|
||||
|
||||
|
||||
class TestRepoMetadataToRepoSetup(base.BaseAlembicMigrationTest):
|
||||
|
|
|
@ -12,15 +12,18 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
_prepare_revision = '43b2cb64dae6'
|
||||
_test_revision = '11a9adc6d36a'
|
||||
|
||||
|
||||
import alembic
|
||||
from oslo_serialization import jsonutils
|
||||
import sqlalchemy as sa
|
||||
|
||||
from nailgun.db import db
|
||||
from nailgun.db import dropdb
|
||||
from nailgun.db.migration import ALEMBIC_CONFIG
|
||||
from nailgun.test import base
|
||||
|
||||
_prepare_revision = '43b2cb64dae6'
|
||||
_test_revision = '11a9adc6d36a'
|
||||
|
||||
|
||||
def setup_module():
|
||||
dropdb()
|
||||
|
@ -30,7 +33,185 @@ def setup_module():
|
|||
|
||||
|
||||
def prepare():
|
||||
pass
|
||||
meta = base.reflect_db_metadata()
|
||||
|
||||
result = db.execute(
|
||||
meta.tables['releases'].insert(),
|
||||
[{
|
||||
'name': 'test_name',
|
||||
'version': '2015.1-8.0',
|
||||
'operating_system': 'ubuntu',
|
||||
'state': 'available',
|
||||
'networks_metadata': jsonutils.dumps({
|
||||
'neutron': {
|
||||
'networks': [
|
||||
{
|
||||
'assign_vip': True,
|
||||
},
|
||||
]
|
||||
},
|
||||
'nova_network': {
|
||||
'networks': [
|
||||
{
|
||||
'assign_vip': False,
|
||||
},
|
||||
]
|
||||
},
|
||||
|
||||
}),
|
||||
'network_roles_metadata': jsonutils.dumps([{
|
||||
'id': 'admin/vip',
|
||||
'default_mapping': 'fuelweb_admin',
|
||||
'properties': {
|
||||
'subnet': True,
|
||||
'gateway': False,
|
||||
'vip': [
|
||||
{
|
||||
'name': 'release-vip1',
|
||||
},
|
||||
{
|
||||
'name': 'release-vip2',
|
||||
'namespace': 'release-vip2-namespace'
|
||||
}
|
||||
]
|
||||
}
|
||||
}]),
|
||||
'is_deployable': True,
|
||||
}])
|
||||
releaseid = result.inserted_primary_key[0]
|
||||
|
||||
db.execute(
|
||||
meta.tables['clusters'].insert(),
|
||||
[{
|
||||
'name': 'test_env',
|
||||
'release_id': releaseid,
|
||||
'mode': 'ha_compact',
|
||||
'status': 'new',
|
||||
'net_provider': 'neutron',
|
||||
'grouping': 'roles',
|
||||
'fuel_version': '8.0',
|
||||
}])
|
||||
|
||||
db.execute(
|
||||
meta.tables['ip_addrs'].insert(),
|
||||
[
|
||||
{
|
||||
'ip_addr': '192.168.0.2',
|
||||
'vip_type': 'management'
|
||||
},
|
||||
{
|
||||
'ip_addr': '192.168.1.2',
|
||||
'vip_type': 'haproxy'
|
||||
},
|
||||
{
|
||||
'ip_addr': '192.168.11.2',
|
||||
'vip_type': 'my-vip1',
|
||||
'namespace': 'my-namespace1'
|
||||
},
|
||||
{
|
||||
'ip_addr': '192.168.12.2',
|
||||
'vip_type': 'my-vip2',
|
||||
'namespace': 'my-namespace2'
|
||||
},
|
||||
{
|
||||
'ip_addr': '192.168.13.2',
|
||||
'vip_type': 'my-vip3',
|
||||
'namespace': 'my-namespace3'
|
||||
},
|
||||
{
|
||||
'ip_addr': '192.168.14.2',
|
||||
'vip_type': 'my-vip4',
|
||||
'namespace': 'my-namespace4'
|
||||
},
|
||||
{
|
||||
'ip_addr': '192.168.15.2',
|
||||
'vip_type': 'release-vip2'
|
||||
}
|
||||
])
|
||||
|
||||
db.execute(
|
||||
meta.tables['network_groups'].insert(),
|
||||
[{
|
||||
'name': 'public',
|
||||
'release': releaseid,
|
||||
'meta': jsonutils.dumps({'assign_vip': True})
|
||||
}])
|
||||
|
||||
db.execute(
|
||||
meta.tables['plugins'].insert(),
|
||||
[{
|
||||
'name': 'test_plugin_a',
|
||||
'title': 'Test plugin A',
|
||||
'version': '2.0.0',
|
||||
'description': 'Test plugin A for Fuel',
|
||||
'homepage': 'http://fuel_plugins.test_plugin.com',
|
||||
'package_version': '4.0.0',
|
||||
'groups': jsonutils.dumps(['tgroup']),
|
||||
'authors': jsonutils.dumps(['tauthor']),
|
||||
'licenses': jsonutils.dumps(['tlicense']),
|
||||
'releases': jsonutils.dumps([
|
||||
{'repository_path': 'repositories/ubuntu'}
|
||||
]),
|
||||
'fuel_version': jsonutils.dumps(['8.0']),
|
||||
'network_roles_metadata': jsonutils.dumps([{
|
||||
'id': 'admin/vip',
|
||||
'default_mapping': 'fuelweb_admin',
|
||||
'properties': {
|
||||
'subnet': True,
|
||||
'gateway': False,
|
||||
'vip': [
|
||||
{
|
||||
'name': 'my-vip1',
|
||||
'namespace': 'my-namespace1',
|
||||
},
|
||||
{
|
||||
'name': 'my-vip2',
|
||||
'namespace': 'my-namespace2',
|
||||
}
|
||||
]
|
||||
}
|
||||
}])
|
||||
}]
|
||||
)
|
||||
|
||||
db.execute(
|
||||
meta.tables['plugins'].insert(),
|
||||
[{
|
||||
'name': 'test_plugin_b',
|
||||
'title': 'Test plugin B',
|
||||
'version': '2.0.0',
|
||||
'description': 'Test plugin B for Fuel',
|
||||
'homepage': 'http://fuel_plugins.test_plugin.com',
|
||||
'package_version': '4.0.0',
|
||||
'groups': jsonutils.dumps(['tgroup']),
|
||||
'authors': jsonutils.dumps(['tauthor']),
|
||||
'licenses': jsonutils.dumps(['tlicense']),
|
||||
'releases': jsonutils.dumps([
|
||||
{'repository_path': 'repositories/ubuntu'}
|
||||
]),
|
||||
'fuel_version': jsonutils.dumps(['8.0']),
|
||||
'network_roles_metadata': jsonutils.dumps([{
|
||||
'id': 'admin/vip',
|
||||
'default_mapping': 'fuelweb_admin',
|
||||
'properties': {
|
||||
'subnet': True,
|
||||
'gateway': False,
|
||||
'vip': [
|
||||
{
|
||||
'name': 'my-vip3',
|
||||
'namespace': 'my-namespace3',
|
||||
},
|
||||
{
|
||||
'name': 'my-vip4',
|
||||
'namespace': 'my-namespace4',
|
||||
}
|
||||
]
|
||||
}
|
||||
}])
|
||||
}]
|
||||
)
|
||||
|
||||
db.commit()
|
||||
|
||||
|
||||
class TestNodeGroupsMigration(base.BaseAlembicMigrationTest):
|
||||
|
@ -90,3 +271,31 @@ class TestNodeGroupsMigration(base.BaseAlembicMigrationTest):
|
|||
if constraint.name in fkeys:
|
||||
value = fkeys[constraint.name]
|
||||
self.assertEqual(constraint.ondelete, value)
|
||||
|
||||
|
||||
class TestVipMigration(base.BaseAlembicMigrationTest):
|
||||
def test_ip_addrs_vip_name_exists(self):
|
||||
result = db.execute(
|
||||
sa.select([self.meta.tables['ip_addrs'].c.vip_name]))
|
||||
self.assertEqual(result.scalar(), "management")
|
||||
|
||||
def test_ip_addrs_vip_namespace_exists(self):
|
||||
result = db.execute(
|
||||
sa.select([
|
||||
self.meta.tables['ip_addrs'].c.vip_name,
|
||||
self.meta.tables['ip_addrs'].c.vip_namespace
|
||||
]))
|
||||
result = list(result)
|
||||
self.assertItemsEqual(
|
||||
(
|
||||
('management', None,),
|
||||
('haproxy', None,),
|
||||
('my-vip1', 'my-namespace1',),
|
||||
('my-vip2', 'my-namespace2',),
|
||||
('my-vip3', 'my-namespace3',),
|
||||
('my-vip4', 'my-namespace4',),
|
||||
# namespace has appeared from release network role
|
||||
('release-vip2', 'release-vip2-namespace',),
|
||||
),
|
||||
result
|
||||
)
|
||||
|
|
|
@ -77,7 +77,7 @@ class TestNetworkConfigurationValidatorProtocol(
|
|||
"configurable": True,
|
||||
"floating_range_var": "floating_ranges",
|
||||
"ext_net_data": [],
|
||||
"vips": consts.NETWORK_VIP_TYPES,
|
||||
"vips": consts.NETWORK_VIP_NAMES_V6_1,
|
||||
},
|
||||
"name": consts.NETWORKS.public,
|
||||
"vlan_start": None
|
||||
|
|
|
@ -442,13 +442,16 @@ def upgrade_vip_types_6_0_to_6_1(connection):
|
|||
"UPDATE ip_addrs SET vip_type = :haproxy WHERE node IS NULL")
|
||||
|
||||
connection.execute(update_query_node_null,
|
||||
haproxy=consts.NETWORK_VIP_TYPES.haproxy)
|
||||
haproxy=consts.NETWORK_VIP_NAMES_V6_1.haproxy)
|
||||
|
||||
|
||||
def downgrade_vip_types_6_1_to_6_0(connection):
|
||||
delete_query = text(
|
||||
"DELETE FROM ip_addrs WHERE vip_type != :haproxy AND node IS NULL")
|
||||
connection.execute(delete_query, haproxy=consts.NETWORK_VIP_TYPES.haproxy)
|
||||
connection.execute(
|
||||
delete_query,
|
||||
haproxy=consts.NETWORK_VIP_NAMES_V6_1.haproxy
|
||||
)
|
||||
|
||||
|
||||
def upgrade_6_0_to_6_1_plugins_cluster_attrs_use_ids_mapping(connection):
|
||||
|
@ -542,7 +545,7 @@ def upgrade_network_groups_metadata_6_0_to_6_1(connection):
|
|||
def create_default_vips(network):
|
||||
if "assign_vip" in network:
|
||||
if network["assign_vip"]:
|
||||
network["vips"] = [consts.NETWORK_VIP_TYPES.haproxy]
|
||||
network["vips"] = [consts.NETWORK_VIP_NAMES_V6_1.haproxy]
|
||||
|
||||
del network["assign_vip"]
|
||||
|
||||
|
|
Loading…
Reference in New Issue