blob: 50bd94a3a678e143e83211e8b45b03d18e883d9a [file] [log] [blame]
#!/usr/bin/env python2.6
'''
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you 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.
'''
__all__ = ["Environment"]
import logging
import os
import shutil
import time
from datetime import datetime
from resource_management.core import shell
from resource_management.core.exceptions import Fail
from resource_management.core.providers import find_provider
from resource_management.core.utils import AttributeDictionary
from resource_management.core.system import System
class Environment(object):
_instances = []
def __init__(self, basedir=None):
"""
@param basedir: basedir/files, basedir/templates are the places where templates / static files
are looked up
@param params: configurations dictionary (this will be accessible in the templates)
"""
self.log = logging.getLogger("resource_management")
self.reset(basedir)
def reset(self, basedir):
self.system = System.get_instance()
self.config = AttributeDictionary()
self.resources = {}
self.resource_list = []
self.delayed_actions = set()
self.update_config({
# current time
'date': datetime.now(),
# backups here files which were rewritten while executing File resource
'backup.path': '/tmp/resource_management/backup',
# prefix for this files
'backup.prefix': datetime.now().strftime("%Y%m%d%H%M%S"),
# dir where templates,failes dirs are
'basedir': basedir,
# variables, which can be used in templates
'params': {},
})
def backup_file(self, path):
if self.config.backup:
if not os.path.exists(self.config.backup.path):
os.makedirs(self.config.backup.path, 0700)
new_name = self.config.backup.prefix + path.replace('/', '-')
backup_path = os.path.join(self.config.backup.path, new_name)
self.log.info("backing up %s to %s" % (path, backup_path))
shutil.copy(path, backup_path)
def update_config(self, attributes, overwrite=True):
for key, value in attributes.items():
attr = self.config
path = key.split('.')
for pth in path[:-1]:
if pth not in attr:
attr[pth] = AttributeDictionary()
attr = attr[pth]
if overwrite or path[-1] not in attr:
attr[path[-1]] = value
def set_params(self, arg):
"""
@param arg: is a dictionary of configurations, or a module with the configurations
"""
if isinstance(arg, dict):
variables = arg
else:
variables = dict((var, getattr(arg, var)) for var in dir(arg))
for variable, value in variables.iteritems():
# don't include system variables, methods, classes, modules
if not variable.startswith("__") and \
not hasattr(value, '__call__')and \
not hasattr(value, '__module__') and \
not hasattr(value, '__file__'):
self.config.params[variable] = value
def run_action(self, resource, action):
self.log.debug("Performing action %s on %s" % (action, resource))
provider_class = find_provider(self, resource.__class__.__name__,
resource.provider)
provider = provider_class(resource)
try:
provider_action = getattr(provider, 'action_%s' % action)
except AttributeError:
raise Fail("%r does not implement action %s" % (provider, action))
provider_action()
if resource.is_updated:
for action, res in resource.subscriptions['immediate']:
self.log.info(
"%s sending %s action to %s (immediate)" % (resource, action, res))
self.run_action(res, action)
for action, res in resource.subscriptions['delayed']:
self.log.info(
"%s sending %s action to %s (delayed)" % (resource, action, res))
self.delayed_actions |= resource.subscriptions['delayed']
def _check_condition(self, cond):
if hasattr(cond, '__call__'):
return cond()
if isinstance(cond, basestring):
ret, out = shell.call(cond)
return ret == 0
raise Exception("Unknown condition type %r" % cond)
def run(self):
with self:
# Run resource actions
for resource in self.resource_list:
self.log.debug("Running resource %r" % resource)
if resource.initial_wait:
time.sleep(resource.initial_wait)
if resource.not_if is not None and self._check_condition(
resource.not_if):
self.log.debug("Skipping %s due to not_if" % resource)
continue
if resource.only_if is not None and not self._check_condition(
resource.only_if):
self.log.debug("Skipping %s due to only_if" % resource)
continue
for action in resource.action:
if not resource.ignore_failures:
self.run_action(resource, action)
else:
try:
self.run_action(resource, action)
except Exception:
pass
# Run delayed actions
while self.delayed_actions:
action, resource = self.delayed_actions.pop()
self.run_action(resource, action)
@classmethod
def get_instance(cls):
return cls._instances[-1]
@classmethod
def get_instance_copy(cls):
"""
Copy only configurations, but not resources execution state
"""
old_instance = cls.get_instance()
new_instance = Environment()
new_instance.config = old_instance.config.copy()
return new_instance
def __enter__(self):
self.__class__._instances.append(self)
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.__class__._instances.pop()
return False
def __getstate__(self):
return dict(
config=self.config,
resources=self.resources,
resource_list=self.resource_list,
delayed_actions=self.delayed_actions,
)
def __setstate__(self, state):
self.__init__()
self.config = state['config']
self.resources = state['resources']
self.resource_list = state['resource_list']
self.delayed_actions = state['delayed_actions']