Removing dependency on trove models in the guest agent
Reasons: - The guest agent is importing backup models and agent heartbeat, this triggers the all of the trove database setup logic which bloats the guest process on the host. - Moving the state to its own module and removing an unused function decreases the memory usage by about 15 - 20 megs. Closes-Bug: #1375311 Change-Id: I126c0b89c170b325d85b3f09afca399b4f5de9e8
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
from sqlalchemy import desc
|
||||
from swiftclient.client import ClientException
|
||||
|
||||
from trove.backup.state import BackupState
|
||||
from trove.common import cfg
|
||||
from trove.common import exception
|
||||
from trove.db.models import DatabaseModelBase
|
||||
@@ -33,17 +34,6 @@ CONF = cfg.CONF
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class BackupState(object):
|
||||
NEW = "NEW"
|
||||
BUILDING = "BUILDING"
|
||||
SAVING = "SAVING"
|
||||
COMPLETED = "COMPLETED"
|
||||
FAILED = "FAILED"
|
||||
DELETE_FAILED = "DELETE_FAILED"
|
||||
RUNNING_STATES = [NEW, BUILDING, SAVING]
|
||||
END_STATES = [COMPLETED, FAILED, DELETE_FAILED]
|
||||
|
||||
|
||||
class Backup(object):
|
||||
|
||||
@classmethod
|
||||
|
||||
26
trove/backup/state.py
Normal file
26
trove/backup/state.py
Normal file
@@ -0,0 +1,26 @@
|
||||
# Copyright 2014 OpenStack Foundation
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
|
||||
class BackupState(object):
|
||||
NEW = "NEW"
|
||||
BUILDING = "BUILDING"
|
||||
SAVING = "SAVING"
|
||||
COMPLETED = "COMPLETED"
|
||||
FAILED = "FAILED"
|
||||
DELETE_FAILED = "DELETE_FAILED"
|
||||
RUNNING_STATES = [NEW, BUILDING, SAVING]
|
||||
END_STATES = [COMPLETED, FAILED, DELETE_FAILED]
|
||||
@@ -22,7 +22,6 @@ from eventlet import Timeout
|
||||
from trove.common import cfg
|
||||
from trove.common import exception
|
||||
from trove.common import rpc as rd_rpc
|
||||
from trove.guestagent import models as agent_models
|
||||
from trove.openstack.common import rpc
|
||||
from trove.openstack.common import log as logging
|
||||
from trove.openstack.common.rpc import proxy
|
||||
@@ -105,16 +104,6 @@ class API(proxy.RpcProxy):
|
||||
"""Create the routing key based on the container id."""
|
||||
return "guestagent.%s" % self.id
|
||||
|
||||
def _check_for_hearbeat(self):
|
||||
"""Preemptively raise GuestTimeout if heartbeat is old."""
|
||||
try:
|
||||
agent = agent_models.AgentHeartBeat.find_by(instance_id=self.id)
|
||||
if agent_models.AgentHeartBeat.is_active(agent):
|
||||
return True
|
||||
except exception.ModelNotFoundError as mnfe:
|
||||
LOG.warn(mnfe)
|
||||
raise exception.GuestTimeout()
|
||||
|
||||
def change_passwords(self, users):
|
||||
"""Make an asynchronous call to change the passwords of one or more
|
||||
users.
|
||||
@@ -278,7 +267,6 @@ class API(proxy.RpcProxy):
|
||||
def get_volume_info(self):
|
||||
"""Make a synchronous call to get volume info for the container."""
|
||||
LOG.debug("Check Volume Info on Instance %s.", self.id)
|
||||
# self._check_for_hearbeat()
|
||||
return self._call("get_filesystem_stats", AGENT_LOW_TIMEOUT,
|
||||
fs_path=None)
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#
|
||||
|
||||
import logging
|
||||
from trove.backup.models import BackupState
|
||||
from trove.backup.state import BackupState
|
||||
from trove.common import cfg
|
||||
from trove.common import context as trove_context
|
||||
from trove.conductor import api as conductor_api
|
||||
|
||||
@@ -18,10 +18,9 @@ import time
|
||||
|
||||
from trove.common import cfg
|
||||
from trove.common import context
|
||||
from trove.common import instance as rd_instance
|
||||
from trove.common import instance
|
||||
from trove.conductor import api as conductor_api
|
||||
from trove.guestagent.common import timeutils
|
||||
from trove.instance import models as rd_models
|
||||
from trove.openstack.common import log as logging
|
||||
from trove.openstack.common.gettextutils import _
|
||||
|
||||
@@ -57,14 +56,12 @@ class BaseDbStatus(object):
|
||||
def __init__(self):
|
||||
if self._instance is not None:
|
||||
raise RuntimeError("Cannot instantiate twice.")
|
||||
self.status = rd_models.InstanceServiceStatus(
|
||||
instance_id=CONF.guest_id,
|
||||
status=rd_instance.ServiceStatuses.NEW)
|
||||
self.status = None
|
||||
self.restart_mode = False
|
||||
|
||||
def begin_install(self):
|
||||
"""Called right before DB is prepared."""
|
||||
self.set_status(rd_instance.ServiceStatuses.BUILDING)
|
||||
self.set_status(instance.ServiceStatuses.BUILDING)
|
||||
|
||||
def begin_restart(self):
|
||||
"""Called before restarting DB server."""
|
||||
@@ -90,11 +87,10 @@ class BaseDbStatus(object):
|
||||
True if DB app should be installed and attempts to ascertain
|
||||
its status won't result in nonsense.
|
||||
"""
|
||||
return (self.status is not None and
|
||||
self.status != rd_instance.ServiceStatuses.NEW and
|
||||
self.status != rd_instance.ServiceStatuses.BUILDING and
|
||||
self.status != rd_instance.ServiceStatuses.BUILD_PENDING and
|
||||
self.status != rd_instance.ServiceStatuses.FAILED)
|
||||
return (self.status != instance.ServiceStatuses.NEW and
|
||||
self.status != instance.ServiceStatuses.BUILDING and
|
||||
self.status != instance.ServiceStatuses.BUILD_PENDING and
|
||||
self.status != instance.ServiceStatuses.FAILED)
|
||||
|
||||
@property
|
||||
def _is_restarting(self):
|
||||
@@ -104,7 +100,7 @@ class BaseDbStatus(object):
|
||||
def is_running(self):
|
||||
"""True if DB server is running."""
|
||||
return (self.status is not None and
|
||||
self.status == rd_instance.ServiceStatuses.RUNNING)
|
||||
self.status == instance.ServiceStatuses.RUNNING)
|
||||
|
||||
def set_status(self, status):
|
||||
"""Use conductor to update the DB app status."""
|
||||
|
||||
@@ -23,8 +23,8 @@ from novaclient import exceptions as nova_exceptions
|
||||
|
||||
from trove.backup import models as bkup_models
|
||||
from trove.backup.models import Backup
|
||||
from trove.backup.models import BackupState
|
||||
from trove.backup.models import DBBackup
|
||||
from trove.backup.state import BackupState
|
||||
from trove.cluster.models import Cluster
|
||||
from trove.cluster.models import DBCluster
|
||||
from trove.cluster import tasks
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
from mox3 import mox
|
||||
import trove.common.instance as tr_instance
|
||||
from trove.backup import models as backup_models
|
||||
from trove.backup import state
|
||||
from trove.common.context import TroveContext
|
||||
from trove.instance.tasks import InstanceTasks
|
||||
from trove.instance import models as imodels
|
||||
@@ -153,7 +154,7 @@ class RestartTaskStatusTests(MgmtInstanceBase):
|
||||
name="forever_new",
|
||||
description="forever new",
|
||||
tenant_id=self.tenant_id,
|
||||
state=backup_models.BackupState.NEW,
|
||||
state=state.BackupState.NEW,
|
||||
instance_id=self.db_info.id,
|
||||
deleted=False)
|
||||
|
||||
@@ -161,7 +162,7 @@ class RestartTaskStatusTests(MgmtInstanceBase):
|
||||
name="forever_build",
|
||||
description="forever build",
|
||||
tenant_id=self.tenant_id,
|
||||
state=backup_models.BackupState.BUILDING,
|
||||
state=state.BackupState.BUILDING,
|
||||
instance_id=self.db_info.id,
|
||||
deleted=False)
|
||||
|
||||
@@ -169,7 +170,7 @@ class RestartTaskStatusTests(MgmtInstanceBase):
|
||||
name="forever_completed",
|
||||
description="forever completed",
|
||||
tenant_id=self.tenant_id,
|
||||
state=backup_models.BackupState.COMPLETED,
|
||||
state=state.BackupState.COMPLETED,
|
||||
instance_id=self.db_info.id,
|
||||
deleted=False)
|
||||
|
||||
@@ -190,9 +191,9 @@ class RestartTaskStatusTests(MgmtInstanceBase):
|
||||
for backup in result:
|
||||
if backup.name == 'forever_completed':
|
||||
assert_equal(backup.status,
|
||||
backup_models.BackupState.COMPLETED)
|
||||
state.BackupState.COMPLETED)
|
||||
else:
|
||||
assert_equal(backup.status, backup_models.BackupState.FAILED)
|
||||
assert_equal(backup.status, state.BackupState.FAILED)
|
||||
|
||||
@test(runs_after=[mgmt_reset_task_status_clears_backups])
|
||||
def clear_test_backups(self):
|
||||
|
||||
@@ -297,7 +297,8 @@ class FakeGuest(object):
|
||||
return dbs
|
||||
|
||||
def create_backup(self, backup_info):
|
||||
from trove.backup.models import Backup, BackupState
|
||||
from trove.backup.models import Backup
|
||||
from trove.backup.state import BackupState
|
||||
backup = Backup.get_by_id(context=None,
|
||||
backup_id=backup_info['id'])
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ from mock import MagicMock, patch
|
||||
import testtools
|
||||
|
||||
from trove.backup import models
|
||||
from trove.backup import state
|
||||
from trove.common import context
|
||||
from trove.common import exception
|
||||
from trove.common import utils
|
||||
@@ -73,7 +74,7 @@ class BackupCreateTest(testtools.TestCase):
|
||||
self.assertEqual(BACKUP_NAME, bu.name)
|
||||
self.assertEqual(BACKUP_DESC, bu.description)
|
||||
self.assertEqual(self.instance_id, bu.instance_id)
|
||||
self.assertEqual(models.BackupState.NEW, bu.state)
|
||||
self.assertEqual(state.BackupState.NEW, bu.state)
|
||||
|
||||
db_record = models.DBBackup.find_by(id=bu.id)
|
||||
self.assertEqual(bu.id, db_record['id'])
|
||||
@@ -81,7 +82,7 @@ class BackupCreateTest(testtools.TestCase):
|
||||
self.assertEqual(BACKUP_DESC, db_record['description'])
|
||||
self.assertEqual(self.instance_id,
|
||||
db_record['instance_id'])
|
||||
self.assertEqual(models.BackupState.NEW,
|
||||
self.assertEqual(state.BackupState.NEW,
|
||||
db_record['state'])
|
||||
self.assertEqual(instance.datastore_version.id,
|
||||
db_record['datastore_version_id'])
|
||||
@@ -124,7 +125,7 @@ class BackupCreateTest(testtools.TestCase):
|
||||
db_record['description'])
|
||||
self.assertEqual(self.instance_id,
|
||||
db_record['instance_id'])
|
||||
self.assertEqual(models.BackupState.NEW,
|
||||
self.assertEqual(state.BackupState.NEW,
|
||||
db_record['state'])
|
||||
self.assertEqual('parent_uuid',
|
||||
db_record['parent_id'])
|
||||
@@ -278,12 +279,12 @@ class BackupORMTest(testtools.TestCase):
|
||||
self.assertTrue(self.backup.is_running)
|
||||
|
||||
def test_is_done(self):
|
||||
self.backup.state = models.BackupState.COMPLETED
|
||||
self.backup.state = state.BackupState.COMPLETED
|
||||
self.backup.save()
|
||||
self.assertTrue(self.backup.is_done)
|
||||
|
||||
def test_not_is_running(self):
|
||||
self.backup.state = models.BackupState.COMPLETED
|
||||
self.backup.state = state.BackupState.COMPLETED
|
||||
self.backup.save()
|
||||
self.assertFalse(self.backup.is_running)
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ from trove.guestagent.common import operating_system
|
||||
from trove.guestagent.strategies.backup import mysql_impl
|
||||
from trove.guestagent.strategies.backup import couchbase_impl
|
||||
from trove.guestagent.strategies.restore.base import RestoreRunner
|
||||
from trove.backup.models import BackupState
|
||||
from trove.backup.state import BackupState
|
||||
from trove.guestagent.backup import backupagent
|
||||
from trove.guestagent.strategies.backup.base import BackupRunner
|
||||
from trove.guestagent.strategies.backup.base import UnknownBackupType
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
import testtools
|
||||
from trove.backup import models as bkup_models
|
||||
from trove.backup import state
|
||||
from trove.common import exception as t_exception
|
||||
from trove.common import utils
|
||||
from trove.common.instance import ServiceStatuses
|
||||
@@ -58,7 +59,7 @@ class ConductorMethodTests(testtools.TestCase):
|
||||
name=name,
|
||||
description='This is a fake backup object.',
|
||||
tenant_id=utils.generate_uuid(),
|
||||
state=bkup_models.BackupState.NEW,
|
||||
state=state.BackupState.NEW,
|
||||
instance_id=self.instance_id)
|
||||
backup.save()
|
||||
return new_id
|
||||
|
||||
@@ -73,27 +73,6 @@ class ApiTest(testtools.TestCase):
|
||||
self.assertEqual('guestagent.' + self.FAKE_ID,
|
||||
self.api._get_routing_key())
|
||||
|
||||
@mock.patch('trove.guestagent.models.AgentHeartBeat')
|
||||
def test_check_for_heartbeat_positive(self, mock_agent):
|
||||
self.assertTrue(self.api._check_for_hearbeat())
|
||||
|
||||
@mock.patch('trove.guestagent.models.AgentHeartBeat')
|
||||
def test_check_for_heartbeat_exception(self, mock_agent):
|
||||
# TODO(juice): maybe it would be ok to extend the test to validate
|
||||
# the is_active method on the heartbeat
|
||||
mock_agent.find_by.side_effect = exception.ModelNotFoundError("Uh Oh!")
|
||||
# execute
|
||||
self.assertRaises(exception.GuestTimeout, self.api._check_for_hearbeat)
|
||||
# validate
|
||||
self.assertEqual(mock_agent.is_active.call_count, 0)
|
||||
|
||||
@mock.patch('trove.guestagent.models.AgentHeartBeat')
|
||||
def test_check_for_heartbeat_negative(self, mock_agent):
|
||||
# TODO(juice): maybe it would be ok to extend the test to validate
|
||||
# the is_active method on the heartbeat
|
||||
mock_agent.is_active.return_value = False
|
||||
self.assertRaises(exception.GuestTimeout, self.api._check_for_hearbeat)
|
||||
|
||||
def test_delete_queue(self):
|
||||
trove_rpc.delete_queue = mock.Mock()
|
||||
# execute
|
||||
|
||||
@@ -1141,7 +1141,7 @@ class BaseDbStatusTest(testtools.TestCase):
|
||||
self.baseDbStatus = BaseDbStatus()
|
||||
self.baseDbStatus.status = None
|
||||
|
||||
self.assertFalse(self.baseDbStatus.is_installed)
|
||||
self.assertTrue(self.baseDbStatus.is_installed)
|
||||
|
||||
def test_is_installed_building(self):
|
||||
self.baseDbStatus = BaseDbStatus()
|
||||
|
||||
@@ -28,6 +28,7 @@ import trove.db.models
|
||||
from trove.taskmanager import models as taskmanager_models
|
||||
import trove.guestagent.api
|
||||
from trove.backup import models as backup_models
|
||||
from trove.backup import state
|
||||
from trove.common import remote
|
||||
from trove.common.exception import GuestError
|
||||
from trove.common.exception import PollTimeOut
|
||||
@@ -595,7 +596,7 @@ class BackupTasksTest(testtools.TestCase):
|
||||
self.backup.created = 'yesterday'
|
||||
self.backup.updated = 'today'
|
||||
self.backup.size = 2.0
|
||||
self.backup.state = backup_models.BackupState.NEW
|
||||
self.backup.state = state.BackupState.NEW
|
||||
self.container_content = (None,
|
||||
[{'name': 'first'},
|
||||
{'name': 'second'},
|
||||
@@ -636,7 +637,7 @@ class BackupTasksTest(testtools.TestCase):
|
||||
'dummy context', self.backup.id)
|
||||
self.assertFalse(backup_models.Backup.delete.called)
|
||||
self.assertEqual(
|
||||
backup_models.BackupState.DELETE_FAILED,
|
||||
state.BackupState.DELETE_FAILED,
|
||||
self.backup.state,
|
||||
"backup should be in DELETE_FAILED status")
|
||||
|
||||
@@ -649,7 +650,7 @@ class BackupTasksTest(testtools.TestCase):
|
||||
'dummy context', self.backup.id)
|
||||
self.assertFalse(backup_models.Backup.delete.called)
|
||||
self.assertEqual(
|
||||
backup_models.BackupState.DELETE_FAILED,
|
||||
state.BackupState.DELETE_FAILED,
|
||||
self.backup.state,
|
||||
"backup should be in DELETE_FAILED status")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user