Support ip address type for instances

Include address type in getting instance response.

* Deprecate confip option network_label_regex as we don't reply on Nova
  to get addresses, network names don't make any sense.
* Add 'addresses' in instance API response, keep 'ip' as is but mark
  it deprecated in API doc, python-troveclient shouldn't break.

Story: 2007562
Task: 39445

Change-Id: Ia0458b5ddae8959ce29c17e444e1a51a026283cd
This commit is contained in:
Lingxian Kong 2020-04-16 17:50:55 +12:00
parent a4057b10af
commit 429c39890e
22 changed files with 253 additions and 180 deletions

View File

@ -161,39 +161,14 @@ Response Parameters
- datastore: datastore2
- datastore.type: datastore_type
- datastore.version: datastore_version1
- region: region_name2
- tenant_id: tenant_id
- volume: volume
- volume.size: volume_size
- volume.used: volume_used
- hostname: instance_hostname
- ip: instance_ip_address
- created: created
- updated: updated
- service_status_updated: service_status_updated
- fault: instance_fault
- fault.message: instance_fault_message
- fault.created: instance_fault_created
- fault.details: instance_fault_details
- replicas: instance_replicas
- replicas.id: instance_replica_id
- replicas.links: instance_replica_links
- replicas.links.href: instance_replica_link_href
- replicas.links.rel: instance_replica_link_rel
- configuration: configuration1
- configuration.id: configuration_id
- configuration.name: configuration_name
- configuration.links: configuration_links
- configuration.links.href: configuration_link_href
- configuration.links.rel: configuration_link_rel
- locality: locality
- local_storage_used: local_storage_used
- password: root_password
- cluster_id: cluster_id
- shard_id: shard_id
- server_id: server_id
- volume_id: volume_id
- encrypted_rpc_messaging: encrypted_rpc_messaging
- instance: instance
@ -231,6 +206,62 @@ Request
- instanceId: instanceId
Response Parameters
-------------------
.. rest_parameters:: parameters.yaml
- instance: instance
- id: instanceId1
- name: instanceName1
- status: instance_status
- links: instance_links
- links.href: instance_link_href
- links.rel: instance_link_rel
- flavor: flavor
- flavor.id: flavorId1
- flavor.links: flavor_links
- flavor.links.href: flavor_link_href
- flavor.links.rel: flavor_link_rel
- datastore: datastore2
- datastore.type: datastore_type
- datastore.version: datastore_version1
- region: region_name2
- tenant_id: tenant_id
- volume: volume
- volume.size: volume_size
- volume.used: volume_used
- hostname: instance_hostname
- ip: instance_ip_address
- addresses: instance_ip_addresses
- created: created
- updated: updated
- service_status_updated: service_status_updated
- fault: instance_fault
- fault.message: instance_fault_message
- fault.created: instance_fault_created
- fault.details: instance_fault_details
- replicas: instance_replicas
- replicas.id: instance_replica_id
- replicas.links: instance_replica_links
- replicas.links.href: instance_replica_link_href
- replicas.links.rel: instance_replica_link_rel
- configuration: configuration1
- configuration.id: configuration_id
- configuration.name: configuration_name
- configuration.links: configuration_links
- configuration.links.href: configuration_link_href
- configuration.links.rel: configuration_link_rel
- locality: locality
- local_storage_used: local_storage_used
- password: root_password
- cluster_id: cluster_id
- shard_id: shard_id
- server_id: server_id
- volume_id: volume_id
- encrypted_rpc_messaging: encrypted_rpc_messaging
Response Example
----------------

View File

@ -419,10 +419,16 @@ instance_hostname:
type: string
instance_ip_address:
description: |
The IP address of an instance.
The IP address of an instance(deprecated).
in: body
require: false
type: string
instance_ip_addresses:
description: |
The IP addresses of an instance, including the address type and IP.
in: body
require: false
type: array
instance_link_href:
description: |
The ``href`` attribute of an instance link.

View File

@ -1,6 +1,16 @@
{
"instances": [
{
"addresses": [
{
"address": "10.1.0.62",
"type": "private"
},
{
"address": "172.24.5.114",
"type": "public"
}
],
"created": "2019-12-23T20:58:35",
"datastore": {
"type": "mysql",

View File

@ -1,6 +1,16 @@
{
"instances": [
{
"addresses": [
{
"address": "10.1.0.62",
"type": "private"
},
{
"address": "172.24.5.114",
"type": "public"
}
],
"created": "2019-12-23T20:58:35",
"datastore": {
"type": "mysql",

View File

@ -1,5 +1,15 @@
{
"instance": {
"addresses": [
{
"address": "10.1.0.62",
"type": "private"
},
{
"address": "172.24.5.114",
"type": "public"
}
],
"created": "2019-12-23T20:58:35",
"datastore": {
"type": "mysql",

View File

@ -1,5 +1,15 @@
{
"instance": {
"addresses": [
{
"address": "10.1.0.62",
"type": "private"
},
{
"address": "172.24.5.114",
"type": "public"
}
],
"created": "2019-12-23T20:58:35",
"datastore": {
"type": "mysql",

View File

@ -556,7 +556,6 @@ function config_trove_network {
sudo ip route
# Now make sure the conf settings are right
iniset $TROVE_CONF DEFAULT network_label_regex ""
iniset $TROVE_CONF DEFAULT ip_regex ""
iniset $TROVE_CONF DEFAULT black_list_regex ""
iniset $TROVE_CONF DEFAULT management_networks ${mgmt_net_id}

View File

@ -2,6 +2,11 @@
Set up database clustering
==========================
.. caution::
Database clustering function is still in experimental, should not be used
in production environment.
You can store data across multiple machines by setting up MongoDB
sharded clusters.

View File

@ -58,13 +58,6 @@ trove_auth_url = http://0.0.0.0/identity/v2.0
# Service type to use when searching catalog.
#neutron_service_type = network
# Config option for showing the IP address that nova doles out
# For nova-network, set this to the appropriate network label defined in nova
# For neutron, set this to .* since users can specify custom network labels
# You can also optionally specify regex'es to match the actual IP addresses
# ip_regex (white-list) is applied before black_list_regex in the filter chain
network_label_regex = ^private$
#network_label_regex = .* #with neutron enabled
#ip_regex = ^(15.|123.)
#black_list_regex = ^10.0.0.

View File

@ -50,7 +50,6 @@ nova_compute_service_type = compute
nova_service_name = Compute Service
# Config option for showing the IP address that nova doles out
network_label_regex = ^private$
ip_regex = ^(15.|123.)
black_list_regex = ^(10.0.0.)

View File

@ -0,0 +1,8 @@
---
features:
- Added a new field named ``addresses`` in the instance API
response which including the IP address and type, either 'private' or
'public'.
deprecations:
- The 'ip' field of getting instance response is deprecated and will be
removed in W release.

View File

@ -93,7 +93,6 @@ class ClusterView(object):
ip_list.extend(instance_ips)
if instance.type in instance_dict_to_be_published_for:
instances.append(instance_dict)
ip_list.sort()
return instances, ip_list
def build_instances(self):

View File

@ -373,7 +373,8 @@ common_opts = [
'mariadb': '7a4f82cc-10d2-4bc6-aadc-d9aacc2a3cb5'},
help='Unique ID to tag notification events.'),
cfg.StrOpt('network_label_regex', default='^private$',
help='Regular expression to match Trove network labels.'),
help='Regular expression to match Trove network labels.',
deprecated_for_removal=True),
cfg.StrOpt('ip_regex', default=None,
help='List IP addresses that match this regular expression.'),
cfg.StrOpt('black_list_regex', default=None,

View File

@ -25,16 +25,12 @@ from novaclient import exceptions as nova_exceptions
from oslo_config.cfg import NoSuchOptError
from oslo_log import log as logging
from oslo_utils import encodeutils
from oslo_utils import netutils
from sqlalchemy import func
from trove.backup.models import Backup
from trove.common import cfg
from trove.common.clients import create_cinder_client
from trove.common.clients import create_dns_client
from trove.common.clients import create_glance_client
from trove.common.clients import create_guest_client
from trove.common.clients import create_neutron_client
from trove.common.clients import create_nova_client
from trove.common import clients
from trove.common import crypto_utils as cu
from trove.common import exception
from trove.common.i18n import _
@ -63,13 +59,16 @@ from trove.taskmanager import api as task_api
CONF = cfg.CONF
LOG = logging.getLogger(__name__)
# Invalid states to contact the agent
AGENT_INVALID_STATUSES = ["BUILD", "REBOOT", "RESIZE", "PROMOTE", "EJECT",
"UPGRADE"]
def filter_ips(ips, white_list_regex, black_list_regex):
"""Return IPs matching white_list_regex and
Filter out IPs matching black_list_regex.
"""
return [ip for ip in ips if re.search(white_list_regex, ip)
and not re.search(black_list_regex, ip)]
def ip_visible(ip, white_list_regex, black_list_regex):
if re.search(white_list_regex, ip) and not re.search(black_list_regex, ip):
return True
return False
def load_server(context, instance_id, server_id, region_name):
@ -84,7 +83,7 @@ def load_server(context, instance_id, server_id, region_name):
:type server_id: unicode
:rtype: novaclient.v2.servers.Server
"""
client = create_nova_client(context, region_name=region_name)
client = clients.create_nova_client(context, region_name=region_name)
try:
server = client.servers.get(server_id)
except nova_exceptions.NotFound:
@ -129,21 +128,42 @@ def load_simple_instance_server_status(context, db_info):
"""Loads a server or raises an exception."""
if 'BUILDING' == db_info.task_status.action:
db_info.server_status = "BUILD"
db_info.addresses = {}
else:
client = create_nova_client(context, db_info.region_id)
client = clients.create_nova_client(context, db_info.region_id)
try:
server = client.servers.get(db_info.compute_instance_id)
db_info.server_status = server.status
db_info.addresses = server.addresses
except nova_exceptions.NotFound:
db_info.server_status = "SHUTDOWN"
db_info.addresses = {}
# Invalid states to contact the agent
AGENT_INVALID_STATUSES = ["BUILD", "REBOOT", "RESIZE", "PROMOTE", "EJECT",
"UPGRADE"]
def load_simple_instance_addresses(context, db_info):
"""Get addresses of the instance from Neutron."""
if 'BUILDING' == db_info.task_status.action:
db_info.addresses = []
return
addresses = []
client = clients.create_neutron_client(context, db_info.region_id)
ports = client.list_ports(device_id=db_info.compute_instance_id)['ports']
for port in ports:
if 'Management port' not in port['description']:
LOG.debug('Found user port %s for instance %s', port['id'],
db_info.id)
for ip in port['fixed_ips']:
# TODO(lxkong): IPv6 is not supported
if netutils.is_valid_ipv4(ip.get('ip_address')):
addresses.append(
{'address': ip['ip_address'], 'type': 'private'})
fips = client.list_floatingips(port_id=port['id'])
if len(fips['floatingips']) == 0:
continue
fip = fips['floatingips'][0]
addresses.append(
{'address': fip['floating_ip_address'], 'type': 'public'})
db_info.addresses = addresses
class SimpleInstance(object):
@ -196,13 +216,6 @@ class SimpleInstance(object):
@property
def addresses(self):
# TODO(tim.simpson): This code attaches two parts of the Nova server to
# db_info: "status" and "addresses". The idea
# originally was to listen to events to update this
# data and store it in the Trove database.
# However, it may have been unwise as a year and a
# half later we still have to load the server anyway
# and this makes the code confusing.
if hasattr(self.db_info, 'addresses'):
return self.db_info.addresses
else:
@ -217,6 +230,7 @@ class SimpleInstance(object):
"""Returns the IP address to be used with DNS."""
ips = self.get_visible_ip_addresses()
if ips:
# FIXME
return ips[0]
@property
@ -234,20 +248,14 @@ class SimpleInstance(object):
return None
IPs = []
mgmt_networks = neutron.get_management_networks(self.context)
for label in self.addresses:
if label in mgmt_networks:
continue
if (CONF.network_label_regex and
not re.search(CONF.network_label_regex, label)):
continue
IPs.extend([addr.get('addr') for addr in self.addresses[label]])
# Includes ip addresses that match the regexp pattern
for addr_info in self.addresses:
if CONF.ip_regex and CONF.black_list_regex:
IPs = filter_ips(IPs, CONF.ip_regex, CONF.black_list_regex)
if not ip_visible(addr_info['address'], CONF.ip_regex,
CONF.black_list_regex):
continue
IPs.append(addr_info)
return IPs
@ -550,15 +558,16 @@ def load_instance(cls, context, id, needs_server=False,
# necessary and instead we'll just use the server_status field from
# the instance table.
load_simple_instance_server_status(context, db_info)
load_simple_instance_addresses(context, db_info)
server = None
else:
try:
server = load_server(context, db_info.id,
db_info.compute_instance_id,
region_name=db_info.region_id)
# TODO(tim.simpson): Remove this hack when we have notifications!
db_info.server_status = server.status
db_info.addresses = server.addresses
load_simple_instance_addresses(context, db_info)
except exception.ComputeInstanceNotFound:
LOG.error("Could not load compute instance %s.",
db_info.compute_instance_id)
@ -568,24 +577,32 @@ def load_instance(cls, context, id, needs_server=False,
service_status = InstanceServiceStatus.find_by(instance_id=id)
LOG.debug("Instance %(instance_id)s service status is %(service_status)s.",
{'instance_id': id, 'service_status': service_status.status})
return cls(context, db_info, server, service_status)
def load_instance_with_info(cls, context, id, cluster_id=None):
db_info = get_db_info(context, id, cluster_id)
load_simple_instance_server_status(context, db_info)
load_simple_instance_addresses(context, db_info)
service_status = InstanceServiceStatus.find_by(instance_id=id)
LOG.debug("Instance %(instance_id)s service status is %(service_status)s.",
{'instance_id': id, 'service_status': service_status.status})
instance = cls(context, db_info, service_status)
load_guest_info(instance, context, id)
load_server_group_info(instance, context)
return instance
def load_guest_info(instance, context, id):
if instance.status not in AGENT_INVALID_STATUSES:
guest = create_guest_client(context, id)
guest = clients.create_guest_client(context, id)
try:
volume_info = guest.get_volume_info()
instance.volume_used = volume_info['used']
@ -646,7 +663,7 @@ class BaseInstance(SimpleInstance):
self._server_group_loaded = False
def get_guest(self):
return create_guest_client(self.context, self.db_info.id)
return clients.create_guest_client(self.context, self.db_info.id)
def delete(self):
def _delete_resources():
@ -754,7 +771,7 @@ class BaseInstance(SimpleInstance):
try:
dns_support = CONF.trove_dns_support
if dns_support:
dns_api = create_dns_client(self.context)
dns_api = clients.create_dns_client(self.context)
dns_api.delete_instance_entry(instance_id=self.id)
except Exception as e:
LOG.warning("Failed to delete dns entry of instance %s, error: %s",
@ -839,7 +856,7 @@ class BaseInstance(SimpleInstance):
@property
def nova_client(self):
if not self._nova_client:
self._nova_client = create_nova_client(
self._nova_client = clients.create_nova_client(
self.context, region_name=self.db_info.region_id)
return self._nova_client
@ -866,14 +883,14 @@ class BaseInstance(SimpleInstance):
@property
def volume_client(self):
if not self._volume_client:
self._volume_client = create_cinder_client(
self._volume_client = clients.create_cinder_client(
self.context, region_name=self.db_info.region_id)
return self._volume_client
@property
def neutron_client(self):
if not self._neutron_client:
self._neutron_client = create_neutron_client(
self._neutron_client = clients.create_neutron_client(
self.context, region_name=self.db_info.region_id)
return self._neutron_client
@ -966,8 +983,8 @@ class Instance(BuiltInstance):
@classmethod
def _validate_remote_datastore(cls, context, region_name, flavor,
datastore, datastore_version):
remote_nova_client = create_nova_client(context,
region_name=region_name)
remote_nova_client = clients.create_nova_client(
context, region_name=region_name)
try:
remote_flavor = remote_nova_client.flavors.get(flavor.id)
if (flavor.ram != remote_flavor.ram or
@ -1000,9 +1017,9 @@ class Instance(BuiltInstance):
"Datastore Version %(dsv)s not found in region %(remote)s."
% {'dsv': datastore_version.name, 'remote': region_name})
glance_client = create_glance_client(context)
glance_client = clients.create_glance_client(context)
local_image = glance_client.images.get(datastore_version.image)
remote_glance_client = create_glance_client(
remote_glance_client = clients.create_glance_client(
context, region_name=region_name)
remote_image = remote_glance_client.images.get(
remote_ds_ver.image)
@ -1050,7 +1067,7 @@ class Instance(BuiltInstance):
flavor_id=flavor_id)
datastore_cfg = CONF.get(datastore_version.manager)
client = create_nova_client(context)
client = clients.create_nova_client(context)
try:
flavor = client.flavors.get(flavor_id)
except nova_exceptions.NotFound:
@ -1242,7 +1259,7 @@ class Instance(BuiltInstance):
status=tr_instance.ServiceStatuses.NEW)
if CONF.trove_dns_support:
dns_client = create_dns_client(context)
dns_client = clients.create_dns_client(context)
hostname = dns_client.determine_hostname(instance_id)
db_info.hostname = hostname
db_info.save()
@ -1659,7 +1676,7 @@ class Instances(object):
if context is None:
raise TypeError(_("Argument context not defined."))
client = create_nova_client(context)
client = clients.create_nova_client(context)
servers = client.servers.list()
query_opts = {'tenant_id': context.project_id,
'deleted': False}
@ -1711,26 +1728,25 @@ class Instances(object):
for db in db_items:
server = None
try:
# TODO(tim.simpson): Delete when we get notifications working!
if InstanceTasks.BUILDING == db.task_status:
db.server_status = "BUILD"
db.addresses = {}
db.addresses = []
else:
try:
region = CONF.service_credentials.region_name
if (not db.region_id or db.region_id == region):
server = find_server(db.id, db.compute_instance_id)
else:
nova_client = create_nova_client(
nova_client = clients.create_nova_client(
context, region_name=db.region_id)
server = nova_client.servers.get(
db.compute_instance_id)
db.server_status = server.status
db.addresses = server.addresses
load_simple_instance_addresses(context, db)
except exception.ComputeInstanceNotFound:
db.server_status = "SHUTDOWN" # Fake it...
db.addresses = {}
# TODO(tim.simpson): End of hack.
db.addresses = []
# volumes = find_volumes(server.id)
datastore_status = InstanceServiceStatus.find_by(

View File

@ -53,9 +53,12 @@ class InstanceView(object):
if self.instance.hostname:
instance_dict['hostname'] = self.instance.hostname
else:
ip = self.instance.get_visible_ip_addresses()
if ip:
instance_dict['ip'] = ip
addresses = self.instance.get_visible_ip_addresses()
if addresses:
# NOTE(lxkong): 'ip' is deprecated in stable/ussuri and should
# be removed in W.
instance_dict['ip'] = [addr['address'] for addr in addresses]
instance_dict['addresses'] = addresses
if self.instance.slave_of_id is not None:
instance_dict['replica_of'] = self._build_master_info()

View File

@ -344,6 +344,8 @@ class Manager(periodic_task.PeriodicTasks):
snapshot = instance_tasks.get_replication_master_snapshot(
context, slave_of_id, flavor, replica_backup_id,
replica_number=replica_number)
LOG.info('Snapshot info for creating replica of %s: %s',
slave_of_id, snapshot)
replica_backup_id = snapshot['dataset']['snapshot_id']
replica_backup_created = (replica_backup_id is not None)

View File

@ -198,7 +198,7 @@ class ClusterTasks(Cluster):
@classmethod
def get_ip(cls, instance):
return instance.get_visible_ip_addresses()[0]
return instance.get_visible_ip_addresses()[0].get('address')
def _all_instances_ready(self, instance_ids, cluster_id,
shard_id=None):
@ -1170,10 +1170,13 @@ class BuiltInstanceTasks(BuiltInstance, NotifyMixin, ConfigurationMixin):
return floating_ips
def detach_public_ips(self):
LOG.debug("Begin detach_public_ips for instance %s", self.id)
LOG.info("Begin detach_public_ips for instance %s", self.id)
removed_ips = []
floating_ips = self._get_floating_ips()
for ip in self.get_visible_ip_addresses():
for item in self.get_visible_ip_addresses():
if item['type'] == 'public':
ip = item['address']
if ip in floating_ips:
fip_id = floating_ips[ip]
self.neutron_client.update_floatingip(
@ -1182,7 +1185,7 @@ class BuiltInstanceTasks(BuiltInstance, NotifyMixin, ConfigurationMixin):
return removed_ips
def attach_public_ips(self, ips):
LOG.debug("Begin attach_public_ips for instance %s", self.id)
LOG.info("Begin attach_public_ips for instance %s", self.id)
server_id = self.db_info.compute_instance_id
# NOTE(zhaochao): in Nova's addFloatingIp, the new floating ip will

View File

@ -919,7 +919,7 @@ class TestGetInstances(object):
def test_index_list(self):
allowed_attrs = ['id', 'links', 'name', 'status', 'flavor',
'datastore', 'ip', 'hostname', 'replica_of',
'region']
'region', 'addresses']
if VOLUME_SUPPORT:
allowed_attrs.append('volume')
instances = dbaas.instances.list()
@ -941,7 +941,7 @@ class TestGetInstances(object):
allowed_attrs = ['created', 'databases', 'flavor', 'hostname', 'id',
'links', 'name', 'status', 'updated', 'ip',
'datastore', 'fault', 'region',
'service_status_updated']
'service_status_updated', 'addresses']
if VOLUME_SUPPORT:
allowed_attrs.append('volume')
instances = dbaas.instances.list(detailed=True)
@ -961,7 +961,7 @@ class TestGetInstances(object):
allowed_attrs = ['created', 'databases', 'flavor', 'hostname', 'id',
'links', 'name', 'status', 'updated', 'ip',
'datastore', 'fault', 'region',
'service_status_updated']
'service_status_updated', 'addresses']
if VOLUME_SUPPORT:
allowed_attrs.append('volume')
else:

View File

@ -82,13 +82,16 @@ class ClusterViewTest(trove_testtools.TestCase):
cluster.instances.append(Mock())
cluster.instances.append(Mock())
cluster.instances[0].type = 'configsvr'
cluster.instances[0].get_visible_ip_addresses = lambda: ['1.2.3.4']
cluster.instances[0].get_visible_ip_addresses.return_value = [
{'type': 'private', 'address': '1.2.3.4'}]
cluster.instances[0].datastore_version.manager = 'mongodb'
cluster.instances[1].type = 'query_router'
cluster.instances[1].get_visible_ip_addresses = lambda: ['1.2.3.4']
cluster.instances[1].get_visible_ip_addresses.return_value = [
{'type': 'private', 'address': '1.2.3.4'}]
cluster.instances[1].datastore_version.manager = 'mongodb'
cluster.instances[2].type = 'member'
cluster.instances[2].get_visible_ip_addresses = lambda: ['1.2.3.4']
cluster.instances[2].get_visible_ip_addresses.return_value = [
{'type': 'private', 'address': '1.2.3.4'}]
cluster.instances[2].datastore_version.manager = 'mongodb'
def test_case(ip_to_be_published_for,
@ -124,7 +127,8 @@ class ClusterInstanceDetailViewTest(trove_testtools.TestCase):
self.instance.addresses = {"private": [{"addr": self.ip}]}
self.instance.volume_used = '3'
self.instance.root_password = 'iloveyou'
self.instance.get_visible_ip_addresses = lambda: ["1.2.3.4"]
self.instance.get_visible_ip_addresses.return_value = [
{'type': 'private', 'address': '1.2.3.4'}]
self.instance.slave_of_id = None
self.instance.slaves = None
self.context = trove_testtools.TroveTestContext(self)
@ -162,3 +166,5 @@ class ClusterInstanceDetailViewTest(trove_testtools.TestCase):
result['instance']['datastore']['version'])
self.assertNotIn('hostname', result['instance'])
self.assertEqual([self.ip], result['instance']['ip'])
self.assertEqual(self.ip,
result['instance']['addresses'][0]['address'])

View File

@ -17,6 +17,7 @@ from mock import Mock, patch
from trove.backup import models as backup_models
from trove.common import cfg
from trove.common import clients
from trove.common import exception
from trove.common.instance import ServiceStatuses
from trove.common import neutron
@ -24,7 +25,6 @@ from trove.datastore import models as datastore_models
from trove.instance import models
from trove.instance.models import DBInstance
from trove.instance.models import DBInstanceFault
from trove.instance.models import filter_ips
from trove.instance.models import Instance
from trove.instance.models import instance_encryption_key_cache
from trove.instance.models import InstanceServiceStatus
@ -50,16 +50,16 @@ class SimpleInstanceTest(trove_testtools.TestCase):
ServiceStatuses.BUILDING), ds_version=Mock(), ds=Mock(),
locality='affinity')
self.instance.context = self.context
db_info.addresses = {"private": [{"addr": "123.123.123.123"}],
"internal": [{"addr": "10.123.123.123"}],
"public": [{"addr": "15.123.123.123"}]}
self.orig_conf = CONF.network_label_regex
db_info.addresses = [
{'type': 'private', 'address': '123.123.123.123'},
{'type': 'private', 'address': '10.123.123.123'},
{'type': 'public', 'address': '15.123.123.123'},
]
self.orig_ip_regex = CONF.ip_regex
self.orig_black_list_regex = CONF.black_list_regex
def tearDown(self):
super(SimpleInstanceTest, self).tearDown()
CONF.network_label_regex = self.orig_conf
CONF.ip_start = None
CONF.management_networks = []
CONF.ip_regex = self.orig_ip_regex
@ -73,64 +73,22 @@ class SimpleInstanceTest(trove_testtools.TestCase):
self.assertFalse(root_on_create_val)
def test_filter_ips_white_list(self):
CONF.network_label_regex = '.*'
CONF.ip_regex = '^(15.|123.)'
CONF.black_list_regex = '^10.123.123.*'
ip = self.instance.get_visible_ip_addresses()
ip = filter_ips(
ip, CONF.ip_regex, CONF.black_list_regex)
ip = [addr['address'] for addr in ip]
self.assertEqual(2, len(ip))
self.assertIn('123.123.123.123', ip)
self.assertIn('15.123.123.123', ip)
def test_filter_ips_black_list(self):
CONF.network_label_regex = '.*'
CONF.ip_regex = '.*'
CONF.black_list_regex = '^10.123.123.*'
ip = self.instance.get_visible_ip_addresses()
ip = filter_ips(
ip, CONF.ip_regex, CONF.black_list_regex)
ip = [addr['address'] for addr in ip]
self.assertEqual(2, len(ip))
self.assertNotIn('10.123.123.123', ip)
def test_one_network_label(self):
CONF.network_label_regex = 'public'
ip = self.instance.get_visible_ip_addresses()
self.assertEqual(['15.123.123.123'], ip)
def test_two_network_labels(self):
CONF.network_label_regex = '^(private|public)$'
ip = self.instance.get_visible_ip_addresses()
self.assertEqual(2, len(ip))
self.assertIn('123.123.123.123', ip)
self.assertIn('15.123.123.123', ip)
def test_all_network_labels(self):
CONF.network_label_regex = '.*'
ip = self.instance.get_visible_ip_addresses()
self.assertEqual(3, len(ip))
self.assertIn('10.123.123.123', ip)
self.assertIn('123.123.123.123', ip)
self.assertIn('15.123.123.123', ip)
@patch('trove.common.clients.create_neutron_client')
def test_filter_management_ip_addresses(self, mock_neutron_client):
CONF.network_label_regex = ''
CONF.management_networks = ['fake-net-id']
neutron_client = Mock()
neutron_client.show_network.return_value = {
'network': {'name': 'public'}
}
mock_neutron_client.return_value = neutron_client
ip = self.instance.get_visible_ip_addresses()
neutron_client.show_network.assert_called_once_with('fake-net-id')
self.assertEqual(2, len(ip))
self.assertIn('123.123.123.123', ip)
self.assertIn('10.123.123.123', ip)
def test_locality(self):
self.assertEqual('affinity', self.instance.locality)
@ -208,8 +166,10 @@ class CreateInstanceTest(trove_testtools.TestCase):
deleted=False
)
self.backup_id = self.backup.id
self.orig_client = models.create_nova_client
models.create_nova_client = nova.fake_create_nova_client
self.orig_client = clients.create_nova_client
clients.create_nova_client = nova.fake_create_nova_client
self.orig_api = task_api.API(self.context).create_instance
task_api.API(self.context).create_instance = Mock()
self.run_with_quotas = models.run_with_quotas
@ -232,7 +192,7 @@ class CreateInstanceTest(trove_testtools.TestCase):
self.backup.delete()
self.datastore.delete()
self.datastore_version.delete()
models.create_nova_client = self.orig_client
clients.create_nova_client = self.orig_client
task_api.API(self.context).create_instance = self.orig_api
models.run_with_quotas = self.run_with_quotas
backup_models.DBBackup.check_swift_object_exist = self.check
@ -310,21 +270,22 @@ class TestInstanceUpgrade(trove_testtools.TestCase):
manager='test',
active=1)
self.safe_nova_client = models.create_nova_client
models.create_nova_client = nova.fake_create_nova_client
self.safe_nova_client = clients.create_nova_client
clients.create_nova_client = nova.fake_create_nova_client
super(TestInstanceUpgrade, self).setUp()
def tearDown(self):
self.datastore.delete()
self.datastore_version1.delete()
self.datastore_version2.delete()
models.create_nova_client = self.safe_nova_client
clients.create_nova_client = self.safe_nova_client
super(TestInstanceUpgrade, self).tearDown()
@patch('trove.common.clients.create_neutron_client')
@patch.object(task_api.API, 'get_client', Mock(return_value=Mock()))
@patch.object(task_api.API, 'upgrade')
@patch('trove.tests.fakes.nova.LOG')
def test_upgrade(self, mock_logging, task_upgrade):
def test_upgrade(self, mock_logging, task_upgrade, mock_neutron_client):
instance_model = DBInstance(
InstanceTasks.NONE,
id=str(uuid.uuid4()),
@ -391,8 +352,8 @@ class TestReplication(trove_testtools.TestCase):
instance_id=self.master.id)
self.master_status.save()
self.safe_nova_client = models.create_nova_client
models.create_nova_client = nova.fake_create_nova_client
self.safe_nova_client = clients.create_nova_client
clients.create_nova_client = nova.fake_create_nova_client
self.swift_verify_patch = patch.object(models.Backup,
'verify_swift_auth_token')
@ -406,7 +367,7 @@ class TestReplication(trove_testtools.TestCase):
self.master_status.delete()
self.datastore.delete()
self.datastore_version.delete()
models.create_nova_client = self.safe_nova_client
clients.create_nova_client = self.safe_nova_client
super(TestReplication, self).tearDown()
@patch('trove.instance.models.LOG')

View File

@ -29,12 +29,10 @@ class InstanceViewsTest(trove_testtools.TestCase):
self.addresses = {"private": [{"addr": "123.123.123.123"}],
"internal": [{"addr": "10.123.123.123"}],
"public": [{"addr": "15.123.123.123"}]}
self.orig_label_regex = CONF.network_label_regex
self.orig_ip_regex = CONF.ip_regex
def tearDown(self):
super(InstanceViewsTest, self).tearDown()
CONF.network_label_regex = self.orig_label_regex
CONF.ip_regex = self.orig_ip_regex
@ -59,7 +57,8 @@ class InstanceDetailViewTest(trove_testtools.TestCase):
self.instance.addresses = {"private": [{"addr": self.ip}]}
self.instance.volume_used = '3'
self.instance.root_password = 'iloveyou'
self.instance.get_visible_ip_addresses = lambda: ["1.2.3.4"]
self.instance.get_visible_ip_addresses.return_value = [
{'type': 'private', 'address': '1.2.3.4'}]
self.instance.slave_of_id = None
self.instance.slaves = []
self.instance.locality = 'affinity'
@ -104,6 +103,8 @@ class InstanceDetailViewTest(trove_testtools.TestCase):
result['instance']['datastore']['version'])
self.assertNotIn('hostname', result['instance'])
self.assertEqual([self.ip], result['instance']['ip'])
self.assertEqual(self.ip,
result['instance']['addresses'][0]['address'])
def test_locality(self):
self.instance.hostname = None

View File

@ -932,7 +932,7 @@ class BuiltInstanceTasksTest(trove_testtools.TestCase):
floating_ips)
@patch.object(BaseInstance, 'get_visible_ip_addresses',
return_value=['192.168.10.1'])
return_value=[{'address': '192.168.10.1', 'type': 'public'}])
def test_detach_public_ips(self, mock_address):
removed_ips = self.instance_task.detach_public_ips()
self.assertEqual(['fake-floatingip-id'], removed_ips)