http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-common/src/main/python/resource_management/core/base.py
----------------------------------------------------------------------
diff --git a/ambari-common/src/main/python/resource_management/core/base.py 
b/ambari-common/src/main/python/resource_management/core/base.py
new file mode 100644
index 0000000..10a8c42
--- /dev/null
+++ b/ambari-common/src/main/python/resource_management/core/base.py
@@ -0,0 +1,173 @@
+#!/usr/bin/env python
+"""
+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.
+
+Ambari Agent
+
+"""
+
+__all__ = ["Resource", "ResourceArgument", "ForcedListArgument",
+           "BooleanArgument"]
+
+from resource_management.core.exceptions import Fail, InvalidArgument
+from resource_management.core.environment import Environment
+from resource_management.core.logger import Logger
+
+class ResourceArgument(object):
+  def __init__(self, default=None, required=False):
+    self.required = False # Prevents the initial validate from failing
+    if hasattr(default, '__call__'):
+      self.default = default
+    else:
+      self.default = self.validate(default)
+    self.required = required
+
+  def validate(self, value):
+    if self.required and value is None:
+      raise InvalidArgument("Required argument %s missing" % self.name)
+    return value
+
+
+class ForcedListArgument(ResourceArgument):
+  def validate(self, value):
+    value = super(ForcedListArgument, self).validate(value)
+    if not isinstance(value, (tuple, list)):
+      value = [value]
+    return value
+
+
+class BooleanArgument(ResourceArgument):
+  def validate(self, value):
+    value = super(BooleanArgument, self).validate(value)
+    if not value in (True, False):
+      raise InvalidArgument(
+        "Expected a boolean for %s received %r" % (self.name, value))
+    return value
+
+
+class Accessor(object):
+  def __init__(self, name):
+    self.name = name
+
+  def __get__(self, obj, cls):
+    try:
+      return obj.arguments[self.name]
+    except KeyError:
+      val = obj._arguments[self.name].default
+      if hasattr(val, '__call__'):
+        val = val(obj)
+      return val
+
+  def __set__(self, obj, value):
+    obj.arguments[self.name] = obj._arguments[self.name].validate(value)
+
+
+class ResourceMetaclass(type):
+  # def __new__(cls, name, bases, attrs):
+  #     super_new = super(ResourceMetaclass, cls).__new__
+  #     return super_new(cls, name, bases, attrs)
+
+  def __init__(mcs, _name, bases, attrs):
+    mcs._arguments = getattr(bases[0], '_arguments', {}).copy()
+    for key, value in list(attrs.items()):
+      if isinstance(value, ResourceArgument):
+        value.name = key
+        mcs._arguments[key] = value
+        setattr(mcs, key, Accessor(key))
+
+
+class Resource(object):
+  __metaclass__ = ResourceMetaclass
+
+  action = ForcedListArgument(default="nothing")
+  ignore_failures = BooleanArgument(default=False)
+  not_if = ResourceArgument() # pass command e.g. not_if = ('ls','/root/jdk')
+  only_if = ResourceArgument() # pass command
+  initial_wait = ResourceArgument() # in seconds
+
+  actions = ["nothing"]
+
+  def __new__(cls, name, env=None, provider=None, **kwargs):
+    if isinstance(name, list):
+      while len(name) != 1:
+        cls(name.pop(0), env, provider, **kwargs)
+
+      name = name[0]
+
+    env = env or Environment.get_instance()
+    provider = provider or getattr(cls, 'provider', None)
+
+    r_type = cls.__name__
+    if r_type not in env.resources:
+      env.resources[r_type] = {}
+
+    obj = super(Resource, cls).__new__(cls)
+    env.resources[r_type][name] = obj
+    env.resource_list.append(obj)
+    return obj
+
+  def __init__(self, name, env=None, provider=None, **kwargs):
+    if isinstance(name, list):
+      name = name.pop(0)
+
+    if hasattr(self, 'name'):
+      return
+
+    self.env = env or Environment.get_instance()
+    self.name = name
+
+    self.provider = provider or getattr(self, 'provider', None)
+
+    self.arguments = {}
+    for key, value in kwargs.items():
+      try:
+        arg = self._arguments[key]
+      except KeyError:
+        raise Fail("%s received unsupported argument %s" % (self, key))
+      else:
+        try:
+          self.arguments[key] = arg.validate(value)
+        except InvalidArgument, exc:
+          raise InvalidArgument("%s %s" % (self, exc))
+
+    if not self.env.test_mode:
+      self.env.run()
+
+  def validate(self):
+    pass
+
+  def __repr__(self):
+    return "%s['%s']" % (self.__class__.__name__, self.name)
+
+  def __unicode__(self):
+    return u"%s['%s']" % (self.__class__.__name__, self.name)
+
+  def __getstate__(self):
+    return dict(
+      name=self.name,
+      provider=self.provider,
+      arguments=self.arguments,
+      env=self.env,
+    )
+
+  def __setstate__(self, state):
+    self.name = state['name']
+    self.provider = state['provider']
+    self.arguments = state['arguments']
+    self.env = state['env']
+
+    self.validate()

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-common/src/main/python/resource_management/core/environment.py
----------------------------------------------------------------------
diff --git 
a/ambari-common/src/main/python/resource_management/core/environment.py 
b/ambari-common/src/main/python/resource_management/core/environment.py
new file mode 100644
index 0000000..e531428
--- /dev/null
+++ b/ambari-common/src/main/python/resource_management/core/environment.py
@@ -0,0 +1,198 @@
+#!/usr/bin/env python
+"""
+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.
+
+Ambari Agent
+
+"""
+
+__all__ = ["Environment"]
+
+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
+from resource_management.core.logger import Logger
+
+
+class Environment(object):
+  _instances = []
+
+  def __init__(self, basedir=None, test_mode=False):
+    """
+    @param basedir: basedir/files, basedir/templates are the places where 
templates / static files
+    are looked up
+    @param test_mode: if this is enabled, resources won't be executed until 
manualy running env.run().
+    """
+    self.reset(basedir, test_mode)
+
+  def reset(self, basedir, test_mode):
+    self.system = System.get_instance()
+    self.config = AttributeDictionary()
+    self.resources = {}
+    self.resource_list = []
+    self.delayed_actions = set()
+    self.test_mode = test_mode
+    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)
+      Logger.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, '__file__'):
+        self.config.params[variable] = value
+
+  def run_action(self, resource, action):
+    Logger.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()
+
+  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
+      while self.resource_list:
+        resource = self.resource_list.pop(0)
+        Logger.info_resource(resource)
+
+        if resource.initial_wait:
+          time.sleep(resource.initial_wait)
+
+        if resource.not_if is not None and self._check_condition(
+          resource.not_if):
+          Logger.info("Skipping %s due to not_if" % resource)
+          continue
+
+        if resource.only_if is not None and not self._check_condition(
+          resource.only_if):
+          Logger.info("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 as ex:
+              Logger.info("Skipping failure of %s due to ignore_failures. 
Failure reason: %s" % (resource, str(ex)))
+              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']

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-common/src/main/python/resource_management/core/exceptions.py
----------------------------------------------------------------------
diff --git 
a/ambari-common/src/main/python/resource_management/core/exceptions.py 
b/ambari-common/src/main/python/resource_management/core/exceptions.py
new file mode 100644
index 0000000..3c001cc
--- /dev/null
+++ b/ambari-common/src/main/python/resource_management/core/exceptions.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+"""
+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.
+
+Ambari Agent
+
+"""
+
+class Fail(Exception):
+  pass
+
+class ExecuteTimeoutException(Exception):
+  pass
+
+class InvalidArgument(Fail):
+  pass
+
+class ClientComponentHasNoStatus(Fail):
+  """
+  Thrown when status() method is called for a CLIENT component.
+  The only valid status for CLIENT component is installed,
+  that's why exception is thrown and later silently processed at script.py
+  """
+  pass
+
+class ComponentIsNotRunning(Fail):
+  """
+  Thrown when status() method is called for a component (only
+  in situations when component process is not running).
+  Later exception is silently processed at script.py
+  """
+  pass

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-common/src/main/python/resource_management/core/logger.py
----------------------------------------------------------------------
diff --git a/ambari-common/src/main/python/resource_management/core/logger.py 
b/ambari-common/src/main/python/resource_management/core/logger.py
new file mode 100644
index 0000000..3550247
--- /dev/null
+++ b/ambari-common/src/main/python/resource_management/core/logger.py
@@ -0,0 +1,111 @@
+#!/usr/bin/env python
+"""
+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.
+
+Ambari Agent
+
+"""
+
+__all__ = ["Logger"]
+import logging
+from resource_management.libraries.script.config_dictionary import 
UnknownConfiguration
+
+class Logger:
+  logger = logging.getLogger("resource_management")
+
+  # unprotected_strings : protected_strings map
+  sensitive_strings = {}
+
+  @staticmethod
+  def error(text):
+    Logger.logger.error(Logger.get_protected_text(text))
+
+  @staticmethod
+  def warning(text):
+    Logger.logger.warning(Logger.get_protected_text(text))
+
+  @staticmethod
+  def info(text):
+    Logger.logger.info(Logger.get_protected_text(text))
+
+  @staticmethod
+  def debug(text):
+    Logger.logger.debug(Logger.get_protected_text(text))
+
+  @staticmethod
+  def error_resource(resource):
+    
Logger.error(Logger.get_protected_text(Logger._get_resource_repr(resource)))
+
+  @staticmethod
+  def warning_resource(resource):
+    
Logger.warning(Logger.get_protected_text(Logger._get_resource_repr(resource)))
+
+  @staticmethod
+  def info_resource(resource):
+    Logger.info(Logger.get_protected_text(Logger._get_resource_repr(resource)))
+
+  @staticmethod
+  def debug_resource(resource):
+    
Logger.debug(Logger.get_protected_text(Logger._get_resource_repr(resource)))
+
+  @staticmethod
+  def get_protected_text(text):
+    """
+    Replace passwords with [PROTECTED]
+    """
+    for unprotected_string, protected_string in 
Logger.sensitive_strings.iteritems():
+      text = text.replace(unprotected_string, protected_string)
+
+    return text
+
+  @staticmethod
+  def _get_resource_repr(resource):
+    MESSAGE_MAX_LEN = 256
+    logger_level = logging._levelNames[Logger.logger.level]
+
+    arguments_str = ""
+    for x,y in resource.arguments.iteritems():
+
+      # strip unicode 'u' sign
+      if isinstance(y, unicode):
+        # don't show long messages
+        if len(y) > MESSAGE_MAX_LEN:
+          y = '...'
+        val = repr(y).lstrip('u')
+      # don't show dicts of configurations
+      # usually too long
+      elif logger_level != 'DEBUG' and isinstance(y, dict):
+        val = "..."
+      # for configs which didn't come
+      elif isinstance(y, UnknownConfiguration):
+        val = "[EMPTY]"
+      # correctly output 'mode' (as they are octal values like 0755)
+      elif y and x == 'mode':
+        try:
+          val = oct(y)
+        except:
+          val = repr(y)
+      else:
+        val = repr(y)
+
+
+      arguments_str += "'{0}': {1}, ".format(x, val)
+
+    if arguments_str:
+      arguments_str = arguments_str[:-2]
+
+    return unicode("{0} {{{1}}}").format(resource, arguments_str)

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-common/src/main/python/resource_management/core/providers/__init__.py
----------------------------------------------------------------------
diff --git 
a/ambari-common/src/main/python/resource_management/core/providers/__init__.py 
b/ambari-common/src/main/python/resource_management/core/providers/__init__.py
new file mode 100644
index 0000000..7f97336
--- /dev/null
+++ 
b/ambari-common/src/main/python/resource_management/core/providers/__init__.py
@@ -0,0 +1,89 @@
+#!/usr/bin/env python
+"""
+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.
+
+Ambari Agent
+
+"""
+
+__all__ = ["Provider", "find_provider"]
+
+from resource_management.core.exceptions import Fail
+from resource_management.libraries.providers import PROVIDERS as 
LIBRARY_PROVIDERS
+
+
+class Provider(object):
+  def __init__(self, resource):
+    self.resource = resource
+
+  def action_nothing(self):
+    pass
+
+  def __repr__(self):
+    return self.__unicode__()
+
+  def __unicode__(self):
+    return u"%s[%s]" % (self.__class__.__name__, self.resource)
+
+
+PROVIDERS = dict(
+  redhat=dict(
+    Package="resource_management.core.providers.package.yumrpm.YumProvider",
+  ),
+  suse=dict(
+    Package="resource_management.core.providers.package.zypper.ZypperProvider",
+  ),
+  ubuntu=dict(
+    Package="resource_management.core.providers.package.apt.AptProvider",
+  ),
+  winsrv=dict(
+    
Service="resource_management.core.providers.windows.service.ServiceProvider",
+    
Execute="resource_management.core.providers.windows.system.ExecuteProvider",
+    File="resource_management.core.providers.windows.system.FileProvider",
+    
Directory="resource_management.core.providers.windows.system.DirectoryProvider"
+  ),
+  default=dict(
+    File="resource_management.core.providers.system.FileProvider",
+    Directory="resource_management.core.providers.system.DirectoryProvider",
+    Link="resource_management.core.providers.system.LinkProvider",
+    Execute="resource_management.core.providers.system.ExecuteProvider",
+    
ExecuteScript="resource_management.core.providers.system.ExecuteScriptProvider",
+    Mount="resource_management.core.providers.mount.MountProvider",
+    User="resource_management.core.providers.accounts.UserProvider",
+    Group="resource_management.core.providers.accounts.GroupProvider",
+    Service="resource_management.core.providers.service.ServiceProvider",
+  ),
+)
+
+
+def find_provider(env, resource, class_path=None):
+  if not class_path:
+    providers = [PROVIDERS, LIBRARY_PROVIDERS]
+    for provider in providers:
+      if resource in provider[env.system.os_family]:
+        class_path = provider[env.system.os_family][resource]
+        break
+      if resource in provider["default"]:
+        class_path = provider["default"][resource]
+        break
+
+  try:
+    mod_path, class_name = class_path.rsplit('.', 1)
+  except ValueError:
+    raise Fail("Unable to find provider for %s as %s" % (resource, class_path))
+  mod = __import__(mod_path, {}, {}, [class_name])
+  return getattr(mod, class_name)

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-common/src/main/python/resource_management/core/providers/accounts.py
----------------------------------------------------------------------
diff --git 
a/ambari-common/src/main/python/resource_management/core/providers/accounts.py 
b/ambari-common/src/main/python/resource_management/core/providers/accounts.py
new file mode 100644
index 0000000..cdde0f0
--- /dev/null
+++ 
b/ambari-common/src/main/python/resource_management/core/providers/accounts.py
@@ -0,0 +1,116 @@
+#!/usr/bin/env python
+"""
+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.
+
+Ambari Agent
+
+"""
+
+from __future__ import with_statement
+
+import grp
+import pwd
+from resource_management.core import shell
+from resource_management.core.providers import Provider
+from resource_management.core.logger import Logger
+
+
+class UserProvider(Provider):
+  def action_create(self):
+    if not self.user:
+      command = ['useradd', "-m"]
+      Logger.info("Adding user %s" % self.resource)
+    else:
+      command = ['usermod']
+      Logger.info("Modifying user %s" % (self.resource.username))
+
+    options = dict(
+      comment="-c",
+      gid="-g",
+      uid="-u",
+      shell="-s",
+      password="-p",
+      home="-d",
+    )
+
+    if self.resource.system and not self.user:
+      command.append("--system")
+
+    if self.resource.groups:
+      command += ["-G", ",".join(self.resource.groups)]
+
+    for option_name, option_flag in options.items():
+      option_value = getattr(self.resource, option_name)
+      if option_flag and option_value:
+        command += [option_flag, str(option_value)]
+
+    command.append(self.resource.username)
+
+    shell.checked_call(command)
+
+  def action_remove(self):
+    if self.user:
+      command = ['userdel', self.resource.username]
+      shell.checked_call(command)
+      Logger.info("Removed user %s" % self.resource)
+
+  @property
+  def user(self):
+    try:
+      return pwd.getpwnam(self.resource.username)
+    except KeyError:
+      return None
+
+
+class GroupProvider(Provider):
+  def action_create(self):
+    group = self.group
+    if not group:
+      command = ['groupadd']
+      Logger.info("Adding group %s" % self.resource)
+    else:
+      command = ['groupmod']
+      Logger.info("Modifying group %s" % (self.resource.group_name))
+
+    options = dict(
+        gid="-g",
+        password="-p",
+    )
+
+    for option_name, option_flag in options.items():
+      option_value = getattr(self.resource, option_name)
+      if option_flag and option_value:
+        command += [option_flag, str(option_value)]
+
+    command.append(self.resource.group_name)
+
+    shell.checked_call(command)
+
+    group = self.group
+
+  def action_remove(self):
+    if self.group:
+      command = ['groupdel', self.resource.group_name]
+      shell.checked_call(command)
+      Logger.info("Removed group %s" % self.resource)
+
+  @property
+  def group(self):
+    try:
+      return grp.getgrnam(self.resource.group_name)
+    except KeyError:
+      return None

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-common/src/main/python/resource_management/core/providers/mount.py
----------------------------------------------------------------------
diff --git 
a/ambari-common/src/main/python/resource_management/core/providers/mount.py 
b/ambari-common/src/main/python/resource_management/core/providers/mount.py
new file mode 100644
index 0000000..0b7fb46
--- /dev/null
+++ b/ambari-common/src/main/python/resource_management/core/providers/mount.py
@@ -0,0 +1,156 @@
+#!/usr/bin/env python
+"""
+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.
+
+Ambari Agent
+
+"""
+
+from __future__ import with_statement
+
+import os
+import re
+from subprocess import Popen, PIPE, STDOUT
+
+from resource_management.core.base import Fail
+from resource_management.core.providers import Provider
+from resource_management.core.logger import Logger
+
+
+def get_mounted():
+  """
+  :return: Return a list of mount objects (dictionary type) that contain the 
device, mount point, and other options.
+  """
+  p = Popen("mount", stdout=PIPE, stderr=STDOUT, shell=True)
+  out = p.communicate()[0]
+  if p.wait() != 0:
+    raise Fail("Getting list of mounts (calling mount) failed")
+
+  mounts = [x.split(' ') for x in out.strip().split('\n')]
+
+  results = []
+  for m in mounts:
+    # Example of m:
+    # /dev/sda1 on / type ext4 (rw,barrier=0)
+    # /dev/sdb on /grid/0 type ext4 (rw,discard)
+    if len(m) >= 6 and m[1] == "on" and m[3] == "type":
+      x = dict(
+        device=m[0],
+        mount_point=m[2],
+        fstype=m[4],
+        options=m[5][1:-1].split(',') if len(m[5]) >= 2 else []
+      )
+      results.append(x)
+
+  return results
+
+
+def get_fstab(self):
+  """
+  :return: Return a list of objects (dictionary type) representing the file 
systems table.
+  """
+  mounts = []
+  with open("/etc/fstab", "r") as fp:
+    for line in fp:
+      line = line.split('#', 1)[0].strip()
+      mount = re.split('\s+', line)
+      if len(mount) == 6:
+        mounts.append(dict(
+          device=mount[0],
+          mount_point=mount[1],
+          fstype=mount[2],
+          options=mount[3].split(","),
+          dump=int(mount[4]),
+          passno=int(mount[5]),
+          ))
+  return mounts
+
+
+class MountProvider(Provider):
+  def action_mount(self):
+    if not os.path.exists(self.resource.mount_point):
+      os.makedirs(self.resource.mount_point)
+
+    if self.is_mounted():
+      Logger.debug("%s already mounted" % self)
+    else:
+      args = ["mount"]
+      if self.resource.fstype:
+        args += ["-t", self.resource.fstype]
+      if self.resource.options:
+        args += ["-o", ",".join(self.resource.options)]
+      if self.resource.device:
+        args.append(self.resource.device)
+      args.append(self.resource.mount_point)
+
+      check_call(args)
+
+      Logger.info("%s mounted" % self)
+
+  def action_umount(self):
+    if self.is_mounted():
+      check_call(["umount", self.resource.mount_point])
+
+      Logger.info("%s unmounted" % self)
+    else:
+      Logger.debug("%s is not mounted" % self)
+
+  def action_enable(self):
+    if self.is_enabled():
+      Logger.debug("%s already enabled" % self)
+    else:
+      if not self.resource.device:
+        raise Fail("[%s] device not set but required for enable action" % self)
+      if not self.resource.fstype:
+        raise Fail("[%s] fstype not set but required for enable action" % self)
+
+      with open("/etc/fstab", "a") as fp:
+        fp.write("%s %s %s %s %d %d\n" % (
+          self.resource.device,
+          self.resource.mount_point,
+          self.resource.fstype,
+          ",".join(self.resource.options or ["defaults"]),
+          self.resource.dump,
+          self.resource.passno,
+        ))
+
+      Logger.info("%s enabled" % self)
+
+  def action_disable(self):
+    pass # TODO
+
+  def is_mounted(self):
+    if not os.path.exists(self.resource.mount_point):
+      return False
+
+    if self.resource.device and not os.path.exists(self.resource.device):
+      raise Fail("%s Device %s does not exist" % (self, self.resource.device))
+
+    mounts = get_mounted()
+    for m in mounts:
+      if m['mount_point'] == self.resource.mount_point:
+        return True
+
+    return False
+
+  def is_enabled(self):
+    mounts = get_fstab()
+    for m in mounts:
+      if m['mount_point'] == self.resource.mount_point:
+        return True
+
+    return False

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-common/src/main/python/resource_management/core/providers/package/__init__.py
----------------------------------------------------------------------
diff --git 
a/ambari-common/src/main/python/resource_management/core/providers/package/__init__.py
 
b/ambari-common/src/main/python/resource_management/core/providers/package/__init__.py
new file mode 100644
index 0000000..c856f23
--- /dev/null
+++ 
b/ambari-common/src/main/python/resource_management/core/providers/package/__init__.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python
+"""
+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.
+
+Ambari Agent
+
+"""
+
+from resource_management.core.base import Fail
+from resource_management.core.providers import Provider
+
+
+class PackageProvider(Provider):
+  def __init__(self, *args, **kwargs):
+    super(PackageProvider, self).__init__(*args, **kwargs)
+
+  def install_package(self, name, version):
+    raise NotImplementedError()
+  def remove_package(self, name):
+    raise NotImplementedError()
+  def upgrade_package(self, name, version):
+    raise NotImplementedError()
+
+  def action_install(self):
+    package_name = self.get_package_name_with_version()
+    self.install_package(package_name)
+
+  def action_upgrade(self):
+    package_name = self.get_package_name_with_version()
+    self.upgrade_package(package_name)
+
+  def action_remove(self):
+    package_name = self.get_package_name_with_version()
+    self.remove_package(package_name)
+
+  def get_package_name_with_version(self):
+    if self.resource.version:
+      return self.resource.package_name + '-' + self.resource.version
+    else:
+      return self.resource.package_name

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-common/src/main/python/resource_management/core/providers/package/apt.py
----------------------------------------------------------------------
diff --git 
a/ambari-common/src/main/python/resource_management/core/providers/package/apt.py
 
b/ambari-common/src/main/python/resource_management/core/providers/package/apt.py
new file mode 100644
index 0000000..3a45ca1
--- /dev/null
+++ 
b/ambari-common/src/main/python/resource_management/core/providers/package/apt.py
@@ -0,0 +1,77 @@
+"""
+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.
+
+Ambari Agent
+
+"""
+
+from resource_management.core.providers.package import PackageProvider
+from resource_management.core import shell
+from resource_management.core.logger import Logger
+
+INSTALL_CMD = "DEBIAN_FRONTEND=noninteractive /usr/bin/apt-get -q -o 
Dpkg::Options::='--force-confdef' --allow-unauthenticated --assume-yes install 
%s"
+REPO_UPDATE_CMD = "apt-get update -qq"
+REMOVE_CMD = "/usr/bin/apt-get -y -q remove %s"
+CHECK_CMD = "dpkg --get-selections %s | grep -v deinstall"
+
+def replace_underscores(function_to_decorate):
+  def wrapper(*args):
+    self = args[0]
+    name = args[1].replace("_", "-")
+    return function_to_decorate(self, name)
+  return wrapper
+
+class AptProvider(PackageProvider):
+
+  @replace_underscores
+  def install_package(self, name):
+    if not self._check_existence(name):
+      cmd = INSTALL_CMD % (name)
+      Logger.info("Installing package %s ('%s')" % (name, cmd))
+      code, out = shell.call(cmd)
+
+      # apt-get update wasn't done too long
+      if code:
+        Logger.info("Execution of '%s' returned %d. %s" % (cmd, code, out))
+        Logger.info("Failed to install package %s. Executing `%s`" % (name, 
REPO_UPDATE_CMD))
+        code, out = shell.call(REPO_UPDATE_CMD)
+
+        if code:
+          Logger.info("Execution of '%s' returned %d. %s" % (REPO_UPDATE_CMD, 
code, out))
+
+        Logger.info("Retrying to install package %s" % (name))
+        shell.checked_call(cmd)
+    else:
+      Logger.info("Skipping installing existent package %s" % (name))
+
+  @replace_underscores
+  def upgrade_package(self, name):
+    return self.install_package(name)
+
+  @replace_underscores
+  def remove_package(self, name):
+    if self._check_existence(name):
+      cmd = REMOVE_CMD % (name)
+      Logger.info("Removing package %s ('%s')" % (name, cmd))
+      shell.checked_call(cmd)
+    else:
+      Logger.info("Skipping removing non-existent package %s" % (name))
+
+  @replace_underscores
+  def _check_existence(self, name):
+    code, out = shell.call(CHECK_CMD % name)
+    return not bool(code)

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-common/src/main/python/resource_management/core/providers/package/yumrpm.py
----------------------------------------------------------------------
diff --git 
a/ambari-common/src/main/python/resource_management/core/providers/package/yumrpm.py
 
b/ambari-common/src/main/python/resource_management/core/providers/package/yumrpm.py
new file mode 100644
index 0000000..7b729f8
--- /dev/null
+++ 
b/ambari-common/src/main/python/resource_management/core/providers/package/yumrpm.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+"""
+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.
+
+Ambari Agent
+
+"""
+
+from resource_management.core.providers.package import PackageProvider
+from resource_management.core import shell
+from resource_management.core.logger import Logger
+
+INSTALL_CMD = "/usr/bin/yum -d 0 -e 0 -y install %s"
+REMOVE_CMD = "/usr/bin/yum -d 0 -e 0 -y erase %s"
+CHECK_CMD = "rpm -q --quiet %s"
+
+class YumProvider(PackageProvider):
+  def install_package(self, name):
+    if not self._check_existence(name):
+      cmd = INSTALL_CMD % (name)
+      Logger.info("Installing package %s ('%s')" % (name, cmd))
+      shell.checked_call(cmd)
+    else:
+      Logger.info("Skipping installing existent package %s" % (name))
+
+  def upgrade_package(self, name):
+    return self.install_package(name)
+
+  def remove_package(self, name):
+    if self._check_existence(name):
+      cmd = REMOVE_CMD % (name)
+      Logger.info("Removing package %s ('%s')" % (name, cmd))
+      shell.checked_call(cmd)
+    else:
+      Logger.info("Skipping removing non-existent package %s" % (name))
+
+  def _check_existence(self, name):
+    code, out = shell.call(CHECK_CMD % name)
+    return not bool(code)

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-common/src/main/python/resource_management/core/providers/package/zypper.py
----------------------------------------------------------------------
diff --git 
a/ambari-common/src/main/python/resource_management/core/providers/package/zypper.py
 
b/ambari-common/src/main/python/resource_management/core/providers/package/zypper.py
new file mode 100644
index 0000000..b57a3fc
--- /dev/null
+++ 
b/ambari-common/src/main/python/resource_management/core/providers/package/zypper.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+"""
+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.
+
+Ambari Agent
+
+"""
+
+from resource_management.core.providers.package import PackageProvider
+from resource_management.core import shell
+from resource_management.core.logger import Logger
+
+INSTALL_CMD = "/usr/bin/zypper --quiet install --auto-agree-with-licenses 
--no-confirm %s"
+REMOVE_CMD = "/usr/bin/zypper --quiet remove --no-confirm %s"
+CHECK_CMD = "rpm -q --quiet %s"
+
+class ZypperProvider(PackageProvider):
+  def install_package(self, name):
+    if not self._check_existence(name):
+      cmd = INSTALL_CMD % (name)
+      Logger.info("Installing package %s ('%s')" % (name, cmd))
+      shell.checked_call(cmd)
+    else:
+      Logger.info("Skipping installing existent package %s" % (name))
+
+  def upgrade_package(self, name):
+    return self.install_package(name)
+
+  def remove_package(self, name):
+    if self._check_existence(name):
+      cmd = REMOVE_CMD % (name)
+      Logger.info("Removing package %s ('%s')" % (name, cmd))
+      shell.checked_call(cmd)
+    else:
+      Logger.info("Skipping removing non-existent package %s" % (name))
+
+  def _check_existence(self, name):
+    code, out = shell.call(CHECK_CMD % name)
+    return not bool(code)

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-common/src/main/python/resource_management/core/providers/service.py
----------------------------------------------------------------------
diff --git 
a/ambari-common/src/main/python/resource_management/core/providers/service.py 
b/ambari-common/src/main/python/resource_management/core/providers/service.py
new file mode 100644
index 0000000..23b1b3a
--- /dev/null
+++ 
b/ambari-common/src/main/python/resource_management/core/providers/service.py
@@ -0,0 +1,96 @@
+#!/usr/bin/env python
+"""
+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.
+
+Ambari Agent
+
+"""
+
+import os
+
+from resource_management.core import shell
+from resource_management.core.base import Fail
+from resource_management.core.providers import Provider
+from resource_management.core.logger import Logger
+
+
+class ServiceProvider(Provider):
+  def action_start(self):
+    if not self.status():
+      self._exec_cmd("start", 0)
+
+  def action_stop(self):
+    if self.status():
+      self._exec_cmd("stop", 0)
+
+  def action_restart(self):
+    if not self.status():
+      self._exec_cmd("start", 0)
+    else:
+      self._exec_cmd("restart", 0)
+
+  def action_reload(self):
+    if not self.status():
+      self._exec_cmd("start", 0)
+    else:
+      self._exec_cmd("reload", 0)
+
+  def status(self):
+    return self._exec_cmd("status") == 0
+
+  def _exec_cmd(self, command, expect=None):
+    if command != "status":
+      Logger.info("%s command '%s'" % (self.resource, command))
+
+    custom_cmd = getattr(self.resource, "%s_command" % command, None)
+    if custom_cmd:
+      Logger.debug("%s executing '%s'" % (self.resource, custom_cmd))
+      if hasattr(custom_cmd, "__call__"):
+        if custom_cmd():
+          ret = 0
+        else:
+          ret = 1
+      else:
+        ret,out = shell.call(custom_cmd)
+    else:
+      ret = self._init_cmd(command)
+
+    if expect is not None and expect != ret:
+      raise Fail("%r command %s for service %s failed with return code: %d. 
%s" % (
+      self, command, self.resource.service_name, ret, out))
+    return ret
+
+  def _init_cmd(self, command):
+    if self._upstart:
+      if command == "status":
+        ret,out = shell.call(["/sbin/" + command, self.resource.service_name])
+        _proc, state = out.strip().split(' ', 1)
+        ret = 0 if state != "stop/waiting" else 1
+      else:
+        ret,out = shell.call(["/sbin/" + command, self.resource.service_name])
+    else:
+      ret,out = shell.call(["/etc/init.d/%s" % self.resource.service_name, 
command])
+    return ret
+
+  @property
+  def _upstart(self):
+    try:
+      return self.__upstart
+    except AttributeError:
+      self.__upstart = os.path.exists("/sbin/start") \
+        and os.path.exists("/etc/init/%s.conf" % self.resource.service_name)
+    return self.__upstart

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-common/src/main/python/resource_management/core/providers/system.py
----------------------------------------------------------------------
diff --git 
a/ambari-common/src/main/python/resource_management/core/providers/system.py 
b/ambari-common/src/main/python/resource_management/core/providers/system.py
new file mode 100644
index 0000000..92258da
--- /dev/null
+++ b/ambari-common/src/main/python/resource_management/core/providers/system.py
@@ -0,0 +1,263 @@
+#!/usr/bin/env python
+"""
+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.
+
+Ambari Agent
+
+"""
+
+from __future__ import with_statement
+
+import grp
+import os
+import pwd
+import time
+import shutil
+from resource_management.core import shell
+from resource_management.core.base import Fail
+from resource_management.core import ExecuteTimeoutException
+from resource_management.core.providers import Provider
+from resource_management.core.logger import Logger
+
+
+def _coerce_uid(user):
+  try:
+    uid = int(user)
+  except ValueError:
+    try:
+      uid = pwd.getpwnam(user).pw_uid
+    except KeyError:
+      raise Fail("User %s doesn't exist." % user)
+  return uid
+
+
+def _coerce_gid(group):
+  try:
+    gid = int(group)
+  except ValueError:
+    try:
+      gid = grp.getgrnam(group).gr_gid
+    except KeyError:
+      raise Fail("Group %s doesn't exist." % group)
+  return gid
+
+
+def _ensure_metadata(path, user, group, mode=None):
+  stat = os.stat(path)
+
+  if mode:
+    existing_mode = stat.st_mode & 07777
+    if existing_mode != mode:
+      Logger.info("Changing permission for %s from %o to %o" % (
+      path, existing_mode, mode))
+      os.chmod(path, mode)
+
+  if user:
+    uid = _coerce_uid(user)
+    if stat.st_uid != uid:
+      Logger.info(
+        "Changing owner for %s from %d to %s" % (path, stat.st_uid, user))
+      os.chown(path, uid, -1)
+
+  if group:
+    gid = _coerce_gid(group)
+    if stat.st_gid != gid:
+      Logger.info(
+        "Changing group for %s from %d to %s" % (path, stat.st_gid, group))
+      os.chown(path, -1, gid)
+
+
+class FileProvider(Provider):
+  def action_create(self):
+    path = self.resource.path
+
+    if os.path.isdir(path):
+      raise Fail("Applying %s failed, directory with name %s exists" % 
(self.resource, path))
+
+    dirname = os.path.dirname(path)
+    if not os.path.isdir(dirname):
+      raise Fail("Applying %s failed, parent directory %s doesn't exist" % 
(self.resource, dirname))
+
+    write = False
+    content = self._get_content()
+    if not os.path.exists(path):
+      write = True
+      reason = "it doesn't exist"
+    elif self.resource.replace:
+      if content is not None:
+        with open(path, "rb") as fp:
+          old_content = fp.read()
+          old_content = old_content.decode(self.resource.encoding) if 
self.resource.encoding else old_content
+        if content != old_content:
+          write = True
+          reason = "contents don't match"
+          if self.resource.backup:
+            self.resource.env.backup_file(path)
+
+    if write:
+      Logger.info("Writing %s because %s" % (self.resource, reason))
+      with open(path, "wb") as fp:
+        if content:
+          content = content.encode(self.resource.encoding) if 
self.resource.encoding else content
+          fp.write(content)
+
+    _ensure_metadata(self.resource.path, self.resource.owner,
+                        self.resource.group, mode=self.resource.mode)
+
+  def action_delete(self):
+    path = self.resource.path
+
+    if os.path.isdir(path):
+      raise Fail("Applying %s failed, %s is directory not file!" % 
(self.resource, path))
+
+    if os.path.exists(path):
+      Logger.info("Deleting %s" % self.resource)
+      os.unlink(path)
+
+  def _get_content(self):
+    content = self.resource.content
+    if content is None:
+      return None
+    elif isinstance(content, basestring):
+      return content
+    elif hasattr(content, "__call__"):
+      return content()
+    raise Fail("Unknown source type for %s: %r" % (self, content))
+
+
+class DirectoryProvider(Provider):
+  def action_create(self):
+    path = self.resource.path
+    if not os.path.exists(path):
+      Logger.info("Creating directory %s" % self.resource)
+      if self.resource.recursive:
+        os.makedirs(path, self.resource.mode or 0755)
+      else:
+        dirname = os.path.dirname(path)
+        if not os.path.isdir(dirname):
+          raise Fail("Applying %s failed, parent directory %s doesn't exist" % 
(self.resource, dirname))
+
+        os.mkdir(path, self.resource.mode or 0755)
+
+    if not os.path.isdir(path):
+      raise Fail("Applying %s failed, file %s already exists" % 
(self.resource, path))
+
+    _ensure_metadata(path, self.resource.owner, self.resource.group,
+                        mode=self.resource.mode)
+
+  def action_delete(self):
+    path = self.resource.path
+    if os.path.exists(path):
+      if not os.path.isdir(path):
+        raise Fail("Applying %s failed, %s is not a directory" % 
(self.resource, path))
+
+      Logger.info("Removing directory %s and all its content" % self.resource)
+      shutil.rmtree(path)
+
+
+class LinkProvider(Provider):
+  def action_create(self):
+    path = self.resource.path
+
+    if os.path.lexists(path):
+      oldpath = os.path.realpath(path)
+      if oldpath == self.resource.to:
+        return
+      if not os.path.islink(path):
+        raise Fail(
+          "%s trying to create a symlink with the same name as an existing 
file or directory" % self)
+      Logger.info("%s replacing old symlink to %s" % (self.resource, oldpath))
+      os.unlink(path)
+
+    if self.resource.hard:
+      if not os.path.exists(self.resource.to):
+        raise Fail("Failed to apply %s, linking to nonexistent location %s" % 
(self.resource, self.resource.to))
+      if os.path.isdir(self.resource.to):
+        raise Fail("Failed to apply %s, cannot create hard link to a directory 
(%s)" % (self.resource, self.resource.to))
+
+      Logger.info("Creating hard %s" % self.resource)
+      os.link(self.resource.to, path)
+    else:
+      if not os.path.exists(self.resource.to):
+        Logger.info("Warning: linking to nonexistent location %s" % 
self.resource.to)
+
+      Logger.info("Creating symbolic %s" % self.resource)
+      os.symlink(self.resource.to, path)
+
+  def action_delete(self):
+    path = self.resource.path
+    if os.path.exists(path):
+      Logger.info("Deleting %s" % self.resource)
+      os.unlink(path)
+
+
+def _preexec_fn(resource):
+  def preexec():
+    if resource.group:
+      gid = _coerce_gid(resource.group)
+      os.setgid(gid)
+      os.setegid(gid)
+
+  return preexec
+
+
+class ExecuteProvider(Provider):
+  def action_run(self):
+    if self.resource.creates:
+      if os.path.exists(self.resource.creates):
+        return
+
+    Logger.debug("Executing %s" % self.resource)
+
+    for i in range (0, self.resource.tries):
+      try:
+        shell.checked_call(self.resource.command, 
logoutput=self.resource.logoutput,
+                            cwd=self.resource.cwd, 
env=self.resource.environment,
+                            preexec_fn=_preexec_fn(self.resource), 
user=self.resource.user,
+                            wait_for_finish=self.resource.wait_for_finish,
+                            timeout=self.resource.timeout,
+                            path=self.resource.path)
+        break
+      except Fail as ex:
+        if i == self.resource.tries-1: # last try
+          raise ex
+        else:
+          Logger.info("Retrying after %d seconds. Reason: %s" % 
(self.resource.try_sleep, str(ex)))
+          time.sleep(self.resource.try_sleep)
+      except ExecuteTimeoutException:
+        err_msg = ("Execution of '%s' was killed due timeout after %d 
seconds") % (self.resource.command, self.resource.timeout)
+
+        if self.resource.on_timeout:
+          Logger.info("Executing '%s'. Reason: %s" % 
(self.resource.on_timeout, err_msg))
+          shell.checked_call(self.resource.on_timeout)
+        else:
+          raise Fail(err_msg)
+
+
+class ExecuteScriptProvider(Provider):
+  def action_run(self):
+    from tempfile import NamedTemporaryFile
+
+    Logger.info("Running script %s" % self.resource)
+    with NamedTemporaryFile(prefix="resource_management-script", bufsize=0) as 
tf:
+      tf.write(self.resource.code)
+      tf.flush()
+
+      _ensure_metadata(tf.name, self.resource.user, self.resource.group)
+      shell.call([self.resource.interpreter, tf.name],
+                      cwd=self.resource.cwd, env=self.resource.environment,
+                      preexec_fn=_preexec_fn(self.resource))

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-common/src/main/python/resource_management/core/providers/windows/__init__.py
----------------------------------------------------------------------
diff --git 
a/ambari-common/src/main/python/resource_management/core/providers/windows/__init__.py
 
b/ambari-common/src/main/python/resource_management/core/providers/windows/__init__.py
new file mode 100644
index 0000000..b0b988b
--- /dev/null
+++ 
b/ambari-common/src/main/python/resource_management/core/providers/windows/__init__.py
@@ -0,0 +1,20 @@
+"""
+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.
+
+Ambari Agent
+
+"""
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-common/src/main/python/resource_management/core/providers/windows/service.py
----------------------------------------------------------------------
diff --git 
a/ambari-common/src/main/python/resource_management/core/providers/windows/service.py
 
b/ambari-common/src/main/python/resource_management/core/providers/windows/service.py
new file mode 100644
index 0000000..cdf3137
--- /dev/null
+++ 
b/ambari-common/src/main/python/resource_management/core/providers/windows/service.py
@@ -0,0 +1,65 @@
+"""
+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.
+
+Ambari Agent
+
+"""
+from resource_management.core.providers import Provider
+from resource_management.core.base import Fail
+import win32service
+import time
+
+
+_schSCManager = win32service.OpenSCManager(None, None, 
win32service.SC_MANAGER_ALL_ACCESS)
+
+
+class ServiceProvider(Provider):
+  def action_start(self):
+    self._service_handle = self._service_handle if hasattr(self, 
"_service_handle") else \
+      win32service.OpenService(_schSCManager, self.resource.service_name, 
win32service.SERVICE_ALL_ACCESS)
+    if not self.status():
+      win32service.StartService(self._service_handle, None)
+      self.wait_status(win32service.SERVICE_RUNNING)
+
+  def action_stop(self):
+    self._service_handle = self._service_handle if hasattr(self, 
"_service_handle") else \
+      win32service.OpenService(_schSCManager, self.resource.service_name, 
win32service.SERVICE_ALL_ACCESS)
+    if self.status():
+      win32service.ControlService(self._service_handle, 
win32service.SERVICE_CONTROL_STOP)
+      self.wait_status(win32service.SERVICE_STOPPED)
+
+  def action_restart(self):
+    self._service_handle = win32service.OpenService(_schSCManager, 
self.resource.service_name,
+                                                    
win32service.SERVICE_ALL_ACCESS)
+    self.action_stop()
+    self.action_start()
+
+  def action_reload(self):
+    raise Fail("Reload for Service resource not supported on windows")
+
+  def status(self):
+    if win32service.QueryServiceStatusEx(self._service_handle)["CurrentState"] 
== win32service.SERVICE_RUNNING:
+      return True
+    return False
+
+  def get_current_status(self):
+    return 
win32service.QueryServiceStatusEx(self._service_handle)["CurrentState"]
+
+  def wait_status(self, status, timeout=5):
+    begin = time.time()
+    while self.get_current_status() != status and (timeout == 0 or time.time() 
- begin < timeout):
+      time.sleep(1)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-common/src/main/python/resource_management/core/providers/windows/system.py
----------------------------------------------------------------------
diff --git 
a/ambari-common/src/main/python/resource_management/core/providers/windows/system.py
 
b/ambari-common/src/main/python/resource_management/core/providers/windows/system.py
new file mode 100644
index 0000000..e7a98fc
--- /dev/null
+++ 
b/ambari-common/src/main/python/resource_management/core/providers/windows/system.py
@@ -0,0 +1,382 @@
+"""
+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.
+
+Ambari Agent
+
+"""
+
+from resource_management.core.providers import Provider
+from resource_management.core.logger import Logger
+from resource_management.core.base import Fail
+from resource_management.core import ExecuteTimeoutException
+import time
+import os
+import subprocess
+import shutil
+from resource_management.libraries.script import Script
+import win32con
+from win32security import *
+from win32api import *
+from winerror import ERROR_INVALID_HANDLE
+from win32profile import CreateEnvironmentBlock
+from win32process import GetExitCodeProcess, STARTF_USESTDHANDLES, 
STARTUPINFO, CreateProcessAsUser
+from win32event import WaitForSingleObject, INFINITE
+from win32security import *
+import msvcrt
+import tempfile
+
+def _create_tmp_files(env=None):
+  dirname = None
+  if env is None:
+    env = os.environ
+
+  for env_var_name in 'TMPDIR', 'TEMP', 'TMP':
+    if env.has_key(env_var_name):
+      dirname = env[env_var_name]
+      if dirname and os.path.exists(dirname):
+        break
+
+  if dirname is None:
+    for dirname2 in r'c:\temp', r'c:\tmp', r'\temp', r'\tmp':
+      try:
+        os.makedirs(dirname2)
+        dirname = dirname2
+        break
+      except:
+        pass
+
+  if dirname is None:
+    raise Exception('Unable to create temp dir. Insufficient access rights.')
+
+  out_file = tempfile.TemporaryFile(mode="r+b", dir=dirname)
+  err_file = tempfile.TemporaryFile(mode="r+b", dir=dirname)
+  return (msvcrt.get_osfhandle(out_file.fileno()),
+          msvcrt.get_osfhandle(err_file.fileno()),
+          out_file,
+          err_file)
+
+
+def _get_files_output(out, err):
+  out.seek(0)
+  err.seek(0)
+  return out.read().strip(), err.read().strip()
+
+
+def _safe_duplicate_handle(h):
+  try:
+    h = DuplicateHandle(GetCurrentProcess(),
+                        h,
+                        GetCurrentProcess(),
+                        0,
+                        True,
+                        win32con.DUPLICATE_SAME_ACCESS)
+    return True, h
+  except Exception as exc:
+    if exc.winerror == ERROR_INVALID_HANDLE:
+      return True, None
+  return False, None
+
+
+def _merge_env(env1, env2, merge_keys=['PYTHONPATH']):
+  """
+  Merge env2 into env1. Also current python instance variables from merge_keys 
list taken into account and they will be
+  merged with equivalent keys from env1 and env2 using system path separator.
+  :param env1: first environment, usually returned by CreateEnvironmentBlock
+  :param env2: custom environment
+  :param merge_keys: env variables to merge as PATH
+  :return: merged environment
+  """
+  env1 = dict(env1)  # copy to new dict in case env1 is os.environ
+  if env2:
+    for key, value in env2.iteritems():
+      if not key in merge_keys:
+        env1[key] = value
+  # strnsform keys and values to str(windows can not accept unicode)
+  result_env = {}
+  for key, value in env1.iteritems():
+    if not key in merge_keys:
+      result_env[str(key)] = str(value)
+  #merge keys from merge_keys
+  def put_values(key, env, result):
+    if env and key in env:
+      result.extend(env[key].split(os.pathsep))
+
+  for key in merge_keys:
+    all_values = []
+    for env in [env1, env2, os.environ]:
+      put_values(key, env, all_values)
+    result_env[str(key)] = str(os.pathsep.join(set(all_values)))
+  return result_env
+
+def AdjustPrivilege(htoken, priv, enable = 1):
+  # Get the ID for the privilege.
+  privId = LookupPrivilegeValue(None, priv)
+  # Now obtain the privilege for this token.
+  # Create a list of the privileges to be added.
+  privState = SE_PRIVILEGE_ENABLED if enable else 0
+  newPrivileges = [(privId, privState)]
+  # and make the adjustment.
+  AdjustTokenPrivileges(htoken, 0, newPrivileges)
+
+def QueryPrivilegeState(hToken, priv):
+  # Get the ID for the privilege.
+  privId = LookupPrivilegeValue(None, priv)
+  privList = GetTokenInformation(hToken, TokenPrivileges)
+  privState = 0
+  for (id, attr) in privList:
+    if id == privId:
+      privState = attr
+  Logger.debug('Privilege state: {}={} ({}) Enabled={}'.format(privId, priv, 
LookupPrivilegeDisplayName(None, priv), privState))
+  return privState
+
+# Execute command. As windows hdp stack heavily relies on proper environment 
it is better to reload fresh environment
+# on every execution. env variable will me merged with fresh environment for 
user.
+def _call_command(command, logoutput=False, cwd=None, env=None, 
wait_for_finish=True, timeout=None, user=None):
+  # TODO implement timeout, wait_for_finish
+  Logger.info("Executing %s" % (command))
+  if user:
+    proc_token = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | 
TOKEN_ADJUST_PRIVILEGES)
+
+    old_states = []
+
+    privileges = [
+      SE_ASSIGNPRIMARYTOKEN_NAME,
+      SE_INCREASE_QUOTA_NAME,
+    ]
+
+    for priv in privileges:
+      old_states.append(QueryPrivilegeState(proc_token, priv))
+      AdjustPrivilege(proc_token, priv)
+      QueryPrivilegeState(proc_token, priv)
+
+    user_token = LogonUser(user, ".", Script.get_password(user), 
win32con.LOGON32_LOGON_SERVICE,
+                           win32con.LOGON32_PROVIDER_DEFAULT)
+    env_token = DuplicateTokenEx(user_token, SecurityIdentification, 
TOKEN_QUERY, TokenPrimary)
+    # getting updated environment for impersonated user and merge it with 
custom env
+    current_env = CreateEnvironmentBlock(env_token, False)
+    current_env = _merge_env(current_env, env)
+
+    si = STARTUPINFO()
+    out_handle, err_handle, out_file, err_file = _create_tmp_files(current_env)
+    ok, si.hStdInput = _safe_duplicate_handle(GetStdHandle(STD_INPUT_HANDLE))
+    if not ok:
+      raise Exception("Unable to create StdInput for child process")
+    ok, si.hStdOutput = _safe_duplicate_handle(out_handle)
+    if not ok:
+      raise Exception("Unable to create StdOut for child process")
+    ok, si.hStdError = _safe_duplicate_handle(err_handle)
+    if not ok:
+      raise Exception("Unable to create StdErr for child process")
+
+    Logger.debug("Redirecting stdout to '{}', stderr to 
'{}'".format(out_file.name, err_file.name))
+
+    si.dwFlags = win32con.STARTF_USESTDHANDLES
+    si.lpDesktop = ""
+
+    try:
+      info = CreateProcessAsUser(user_token, None, command, None, None, 1, 
win32con.CREATE_NO_WINDOW, current_env, cwd, si)
+      hProcess, hThread, dwProcessId, dwThreadId = info
+      hThread.Close()
+
+      try:
+        WaitForSingleObject(hProcess, INFINITE)
+      except KeyboardInterrupt:
+        pass
+      out, err = _get_files_output(out_file, err_file)
+      code = GetExitCodeProcess(hProcess)
+    finally:
+      for priv in privileges:
+        old_state = old_states.pop(0)
+        AdjustPrivilege(proc_token, priv, old_state)
+  else:
+    # getting updated environment for current process and merge it with custom 
env
+    cur_token = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY)
+    current_env = CreateEnvironmentBlock(cur_token, False)
+    current_env = _merge_env(current_env, env)
+    proc = subprocess.Popen(command, stdout=subprocess.PIPE, 
stderr=subprocess.STDOUT,
+                            cwd=cwd, env=current_env, shell=False)
+    out, err = proc.communicate()
+    code = proc.returncode
+
+  if logoutput and out:
+    Logger.info(out)
+  if logoutput and err:
+    Logger.info(err)
+  return code, out, err
+
+
+# see msdn Icacls doc for rights
+def _set_file_acl(file, user, rights):
+  acls_modify_cmd = "icacls {0} /grant {1}:{2}".format(file, user, rights)
+  acls_remove_cmd = "icacls {0} /remove {1}".format(file, user)
+  code, out, err = _call_command(acls_remove_cmd)
+  if code != 0:
+    raise Fail("Can not remove rights for path {0} and user {1}".format(file, 
user))
+  code, out, err = _call_command(acls_modify_cmd)
+  if code != 0:
+    raise Fail("Can not set rights {0} for path {1} and user {2}".format(file, 
user))
+  else:
+    return
+
+
+class FileProvider(Provider):
+  def action_create(self):
+    path = self.resource.path
+
+    if os.path.isdir(path):
+      raise Fail("Applying %s failed, directory with name %s exists" % 
(self.resource, path))
+
+    dirname = os.path.dirname(path)
+    if not os.path.isdir(dirname):
+      raise Fail("Applying %s failed, parent directory %s doesn't exist" % 
(self.resource, dirname))
+
+    write = False
+    content = self._get_content()
+    if not os.path.exists(path):
+      write = True
+      reason = "it doesn't exist"
+    elif self.resource.replace:
+      if content is not None:
+        with open(path, "rb") as fp:
+          old_content = fp.read()
+        if content != old_content:
+          write = True
+          reason = "contents don't match"
+          if self.resource.backup:
+            self.resource.env.backup_file(path)
+
+    if write:
+      Logger.info("Writing %s because %s" % (self.resource, reason))
+      with open(path, "wb") as fp:
+        if content:
+          fp.write(content)
+
+    if self.resource.owner and self.resource.mode:
+      _set_file_acl(self.resource.path, self.resource.owner, 
self.resource.mode)
+
+  def action_delete(self):
+    path = self.resource.path
+
+    if os.path.isdir(path):
+      raise Fail("Applying %s failed, %s is directory not file!" % 
(self.resource, path))
+
+    if os.path.exists(path):
+      Logger.info("Deleting %s" % self.resource)
+      os.unlink(path)
+
+  def _get_content(self):
+    content = self.resource.content
+    if content is None:
+      return None
+    elif isinstance(content, basestring):
+      return content
+    elif hasattr(content, "__call__"):
+      return content()
+    raise Fail("Unknown source type for %s: %r" % (self, content))
+
+
+class ExecuteProvider(Provider):
+  def action_run(self):
+    if self.resource.creates:
+      if os.path.exists(self.resource.creates):
+        return
+
+    Logger.debug("Executing %s" % self.resource)
+
+    if self.resource.path != []:
+      if not self.resource.environment:
+        self.resource.environment = {}
+
+      self.resource.environment['PATH'] = os.pathsep.join(self.resource.path)
+
+    for i in range(0, self.resource.tries):
+      try:
+        code, _, _ = _call_command(self.resource.command, 
logoutput=self.resource.logoutput,
+                                   cwd=self.resource.cwd, 
env=self.resource.environment,
+                                   
wait_for_finish=self.resource.wait_for_finish,
+                                   timeout=self.resource.timeout, 
user=self.resource.user)
+        if code != 0 and not self.resource.ignore_failures:
+          raise Fail("Failed to execute " + self.resource.command)
+        break
+      except Fail as ex:
+        if i == self.resource.tries - 1:  # last try
+          raise ex
+        else:
+          Logger.info("Retrying after %d seconds. Reason: %s" % 
(self.resource.try_sleep, str(ex)))
+          time.sleep(self.resource.try_sleep)
+      except ExecuteTimeoutException:
+        err_msg = ("Execution of '%s' was killed due timeout after %d 
seconds") % (
+          self.resource.command, self.resource.timeout)
+
+        if self.resource.on_timeout:
+          Logger.info("Executing '%s'. Reason: %s" % 
(self.resource.on_timeout, err_msg))
+          _call_command(self.resource.on_timeout)
+        else:
+          raise Fail(err_msg)
+
+
+class DirectoryProvider(Provider):
+  def action_create(self):
+    path = DirectoryProvider._trim_uri(self.resource.path)
+    if not os.path.exists(path):
+      Logger.info("Creating directory %s" % self.resource)
+      if self.resource.recursive:
+        os.makedirs(path)
+      else:
+        dirname = os.path.dirname(path)
+        if not os.path.isdir(dirname):
+          raise Fail("Applying %s failed, parent directory %s doesn't exist" % 
(self.resource, dirname))
+
+        os.mkdir(path)
+
+    if not os.path.isdir(path):
+      raise Fail("Applying %s failed, file %s already exists" % 
(self.resource, path))
+
+    if self.resource.owner and self.resource.mode:
+      _set_file_acl(path, self.resource.owner, self.resource.mode)
+
+  def action_delete(self):
+    path = self.resource.path
+    if os.path.exists(path):
+      if not os.path.isdir(path):
+        raise Fail("Applying %s failed, %s is not a directory" % 
(self.resource, path))
+
+      Logger.info("Removing directory %s and all its content" % self.resource)
+      shutil.rmtree(path)
+
+  @staticmethod
+  def _trim_uri(file_uri):
+    if file_uri.startswith("file:///"):
+      return file_uri[8:]
+    return file_uri
+    # class res: pass
+    # resource = res()
+    # resource.creates = None
+    # resource.path =[]
+    # resource.tries = 1
+    # resource.logoutput = True
+    # resource.cwd = None
+    # resource.environment = None
+    # resource.wait_for_finish = True
+    # resource.timeout = None
+    # resource.command = "cmd /C echo 1 & echo 2"
+    # provider = ExecuteProvider(resource)
+    # provider.action_run()
+    # pass
+    # _set_file_acl("C:\\lol.txt", "Administrator","f")
+    # pass
+    # pass
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-common/src/main/python/resource_management/core/resources/__init__.py
----------------------------------------------------------------------
diff --git 
a/ambari-common/src/main/python/resource_management/core/resources/__init__.py 
b/ambari-common/src/main/python/resource_management/core/resources/__init__.py
new file mode 100644
index 0000000..d5e903c
--- /dev/null
+++ 
b/ambari-common/src/main/python/resource_management/core/resources/__init__.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+"""
+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.
+
+Ambari Agent
+
+"""
+
+from resource_management.core.resources.accounts import *
+from resource_management.core.resources.packaging import *
+from resource_management.core.resources.service import *
+from resource_management.core.resources.system import *

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-common/src/main/python/resource_management/core/resources/accounts.py
----------------------------------------------------------------------
diff --git 
a/ambari-common/src/main/python/resource_management/core/resources/accounts.py 
b/ambari-common/src/main/python/resource_management/core/resources/accounts.py
new file mode 100644
index 0000000..b6200fa
--- /dev/null
+++ 
b/ambari-common/src/main/python/resource_management/core/resources/accounts.py
@@ -0,0 +1,48 @@
+#!/usr/bin/env python
+"""
+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.
+
+Ambari Agent
+
+"""
+__all__ = ["Group", "User"]
+
+from resource_management.core.base import Resource, ForcedListArgument, 
ResourceArgument, BooleanArgument
+
+
+class Group(Resource):
+  action = ForcedListArgument(default="create")
+  group_name = ResourceArgument(default=lambda obj: obj.name)
+  gid = ResourceArgument()
+  password = ResourceArgument()
+
+  actions = Resource.actions + ["create", "remove"]
+
+
+class User(Resource):
+  action = ForcedListArgument(default="create")
+  username = ResourceArgument(default=lambda obj: obj.name)
+  comment = ResourceArgument()
+  uid = ResourceArgument()
+  gid = ResourceArgument()
+  groups = ForcedListArgument(default=[]) # supplementary groups
+  home = ResourceArgument()
+  shell = ResourceArgument()
+  password = ResourceArgument()
+  system = BooleanArgument(default=False)
+
+  actions = Resource.actions + ["create", "remove"]

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-common/src/main/python/resource_management/core/resources/packaging.py
----------------------------------------------------------------------
diff --git 
a/ambari-common/src/main/python/resource_management/core/resources/packaging.py 
b/ambari-common/src/main/python/resource_management/core/resources/packaging.py
new file mode 100644
index 0000000..c2ff20e
--- /dev/null
+++ 
b/ambari-common/src/main/python/resource_management/core/resources/packaging.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+"""
+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.
+
+Ambari Agent
+
+"""
+
+__all__ = ["Package"]
+
+from resource_management.core.base import Resource, ForcedListArgument, 
ResourceArgument
+
+
+class Package(Resource):
+  action = ForcedListArgument(default="install")
+  package_name = ResourceArgument(default=lambda obj: obj.name)
+  location = ResourceArgument(default=lambda obj: obj.package_name)
+  version = ResourceArgument()
+  actions = ["install", "upgrade", "remove"]
+  build_vars = ForcedListArgument(default=[])

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-common/src/main/python/resource_management/core/resources/service.py
----------------------------------------------------------------------
diff --git 
a/ambari-common/src/main/python/resource_management/core/resources/service.py 
b/ambari-common/src/main/python/resource_management/core/resources/service.py
new file mode 100644
index 0000000..20d5c1b
--- /dev/null
+++ 
b/ambari-common/src/main/python/resource_management/core/resources/service.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+"""
+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.
+
+Ambari Agent
+
+"""
+
+__all__ = ["Service"]
+
+from resource_management.core.base import Resource, ResourceArgument, 
ForcedListArgument
+
+
+class Service(Resource):
+  action = ForcedListArgument(default="start")
+  service_name = ResourceArgument(default=lambda obj: obj.name)
+  #enabled = ResourceArgument() # Maybe add support to put in/out autostart.
+  start_command = ResourceArgument()
+  stop_command = ResourceArgument()
+  restart_command = ResourceArgument()
+  reload_command = ResourceArgument() # reload the config file without 
interrupting pending operations
+  status_command = ResourceArgument()
+
+  actions = ["nothing", "start", "stop", "restart", "reload"]

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-common/src/main/python/resource_management/core/resources/system.py
----------------------------------------------------------------------
diff --git 
a/ambari-common/src/main/python/resource_management/core/resources/system.py 
b/ambari-common/src/main/python/resource_management/core/resources/system.py
new file mode 100644
index 0000000..fa02477
--- /dev/null
+++ b/ambari-common/src/main/python/resource_management/core/resources/system.py
@@ -0,0 +1,129 @@
+#!/usr/bin/env python
+"""
+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.
+
+Ambari Agent
+
+"""
+
+__all__ = ["File", "Directory", "Link", "Execute", "ExecuteScript", "Mount"]
+
+from resource_management.core.base import Resource, ForcedListArgument, 
ResourceArgument, BooleanArgument
+
+
+class File(Resource):
+  action = ForcedListArgument(default="create")
+  path = ResourceArgument(default=lambda obj: obj.name)
+  backup = ResourceArgument()
+  mode = ResourceArgument()
+  owner = ResourceArgument()
+  group = ResourceArgument()
+  content = ResourceArgument()
+  # whether to replace files with different content
+  replace = ResourceArgument(default=True)
+  encoding = ResourceArgument()
+
+  actions = Resource.actions + ["create", "delete"]
+
+
+class Directory(Resource):
+  action = ForcedListArgument(default="create")
+  path = ResourceArgument(default=lambda obj: obj.name)
+  mode = ResourceArgument()
+  owner = ResourceArgument()
+  group = ResourceArgument()
+  recursive = BooleanArgument(default=False) # this work for 'create', 
'delete' is anyway recursive
+
+  actions = Resource.actions + ["create", "delete"]
+
+
+class Link(Resource):
+  action = ForcedListArgument(default="create")
+  path = ResourceArgument(default=lambda obj: obj.name)
+  to = ResourceArgument(required=True)
+  hard = BooleanArgument(default=False)
+
+  actions = Resource.actions + ["create", "delete"]
+
+
+class Execute(Resource):
+  action = ForcedListArgument(default="run")
+
+  """
+  Recommended:
+  command = ('rm','-f','myfile')
+  Not recommended:
+  command = 'rm -f myfile'
+
+  The first one helps to stop escaping issues
+  """
+  command = ResourceArgument(default=lambda obj: obj.name)
+
+  creates = ResourceArgument()
+  cwd = ResourceArgument()
+  # this runs command with a specific env variables, env={'JAVA_HOME': 
'/usr/jdk'}
+  environment = ResourceArgument()
+  user = ResourceArgument()
+  group = ResourceArgument()
+  returns = ForcedListArgument(default=0)
+  tries = ResourceArgument(default=1)
+  try_sleep = ResourceArgument(default=0) # seconds
+  path = ForcedListArgument(default=[])
+  actions = Resource.actions + ["run"]
+  logoutput = BooleanArgument(default=False)
+  """
+  if on_timeout is not set leads to failing after x seconds,
+  otherwise calls on_timeout
+  """
+  timeout = ResourceArgument() # seconds
+  on_timeout = ResourceArgument()
+  """
+  Wait for command to finish or not.
+
+  NOTE:
+  In case of False, since any command results are skipped, it disables some 
functionality:
+  - non-zero return code failure
+  - logoutput
+  - tries
+  - try_sleep
+  """
+  wait_for_finish = BooleanArgument(default=True)
+
+
+class ExecuteScript(Resource):
+  action = ForcedListArgument(default="run")
+  code = ResourceArgument(required=True)
+  cwd = ResourceArgument()
+  environment = ResourceArgument()
+  interpreter = ResourceArgument(default="/bin/bash")
+  user = ResourceArgument()
+  group = ResourceArgument()
+
+  actions = Resource.actions + ["run"]
+
+
+class Mount(Resource):
+  action = ForcedListArgument(default="mount")
+  mount_point = ResourceArgument(default=lambda obj: obj.name)
+  device = ResourceArgument()
+  fstype = ResourceArgument()
+  options = ResourceArgument(default=["defaults"])
+  dump = ResourceArgument(default=0)
+  passno = ResourceArgument(default=2)
+
+  actions = Resource.actions + ["mount", "umount", "remount", "enable",
+                                "disable"]

Reply via email to