This change adds an idle state to driver providers which is used to indicate that the provider should stop performing actions that are not safe to perform while we bootstrap a second newer version of the provider to handle a config update. This is particularly interesting for the static driver because it is managing all of its state internally to nodepool and not relying on external cloud systems to track resources. This means it is important for the static provider to not have an old provider object update zookeeper at the same time as a new provider object. This was previously possible and created situtations where the resources in zookeeper did not reflect our local config. Since all other drivers rely on external state the primary update here is to the static driver. We simply stop performing config synchronization if the idle flag is set on a static provider. This will allow the new provider to take over reflecting the new config consistently. Note, we don't take other approaches and essentially create a system specific to the static driver because we're trying to avoid modifying the nodepool runtime significantly to fix a problem that is specific to the static driver. Change-Id: I93519d0c6f4ddf8a417d837f6ae12a30a55870bb
79 lines
2.9 KiB
Python
79 lines
2.9 KiB
Python
# Copyright (C) 2011-2013 OpenStack Foundation
|
|
#
|
|
# 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.
|
|
|
|
import logging
|
|
|
|
from nodepool.driver import Drivers
|
|
|
|
|
|
def get_provider(provider):
|
|
driver = Drivers.get(provider.driver.name)
|
|
return driver.getProvider(provider)
|
|
|
|
|
|
class ProviderManager(object):
|
|
log = logging.getLogger("nodepool.ProviderManager")
|
|
|
|
@staticmethod
|
|
def reconfigure(old_config, new_config, zk_conn,
|
|
only_image_manager=False):
|
|
'''
|
|
Reconfigure the provider managers on any configuration changes.
|
|
|
|
If a provider configuration changes, stop the current provider
|
|
manager we have cached and replace it with a new one.
|
|
|
|
:param Config old_config: The previously read configuration.
|
|
:param Config new_config: The newly read configuration.
|
|
:param ZooKeeper zk_conn: A ZooKeeper connection object.
|
|
:param bool only_image_manager: If True, skip manager that do not
|
|
manage images. This is used by the builder process.
|
|
'''
|
|
stop_managers = []
|
|
for p in new_config.providers.values():
|
|
if only_image_manager and not p.manage_images:
|
|
continue
|
|
oldmanager = None
|
|
if old_config:
|
|
oldmanager = old_config.provider_managers.get(p.name)
|
|
if oldmanager and p != oldmanager.provider:
|
|
# Signal that actions not safe to run on both the old and
|
|
# new providers while we synchronize should cease to run.
|
|
oldmanager.idle()
|
|
stop_managers.append(oldmanager)
|
|
oldmanager = None
|
|
if oldmanager:
|
|
new_config.provider_managers[p.name] = oldmanager
|
|
else:
|
|
ProviderManager.log.debug("Creating new ProviderManager object"
|
|
" for %s" % p.name)
|
|
try:
|
|
pm = get_provider(p)
|
|
pm.start(zk_conn)
|
|
new_config.provider_managers[p.name] = pm
|
|
except Exception:
|
|
ProviderManager.log.exception(
|
|
"Error starting provider %s", p.name)
|
|
|
|
for stop_manager in stop_managers:
|
|
stop_manager.stop()
|
|
|
|
@staticmethod
|
|
def stopProviders(config):
|
|
for m in config.provider_managers.values():
|
|
m.stop()
|
|
m.join()
|