You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by yu...@apache.org on 2014/11/14 03:20:09 UTC

[27/29] ambari git commit: AMBARI-8269. Merge branch-windows-dev changes to trunk. (Jayush Luniya via yusaku)

http://git-wip-us.apache.org/repos/asf/ambari/blob/8de3425f/ambari-agent/src/main/python/ambari_agent/StatusCheck.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/StatusCheck.py b/ambari-agent/src/main/python/ambari_agent/StatusCheck.py
index 2b64989..7feadb6 100644
--- a/ambari-agent/src/main/python/ambari_agent/StatusCheck.py
+++ b/ambari-agent/src/main/python/ambari_agent/StatusCheck.py
@@ -54,7 +54,7 @@ class StatusCheck:
       
   def fillDirValues(self):
     try:
-      for pidVar in self.pidPathesVars:
+      for pidVar in self.pidPathVars:
         pidVarName = pidVar['var']
         pidDefaultvalue = pidVar['defaultValue']
         if self.globalConfig.has_key(pidVarName):
@@ -64,11 +64,11 @@ class StatusCheck:
     except Exception as e:
         logger.error("Error while filling directories values " + str(e))
         
-  def __init__(self, serviceToPidDict, pidPathesVars, globalConfig,
+  def __init__(self, serviceToPidDict, pidPathVars, globalConfig,
     servicesToLinuxUser):
     
     self.serToPidDict = serviceToPidDict.copy()
-    self.pidPathesVars = pidPathesVars
+    self.pidPathVars = pidPathVars
     self.pidPathes = []
     self.sh = shellRunner()
     self.pidFilesDict = {}

http://git-wip-us.apache.org/repos/asf/ambari/blob/8de3425f/ambari-agent/src/main/python/ambari_agent/hostname.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/hostname.py b/ambari-agent/src/main/python/ambari_agent/hostname.py
index 9fbe145..caf7600 100644
--- a/ambari-agent/src/main/python/ambari_agent/hostname.py
+++ b/ambari-agent/src/main/python/ambari_agent/hostname.py
@@ -44,11 +44,11 @@ def hostname(config):
       if (0 == osStat.returncode and 0 != len(out.strip())):
         cached_hostname = out.strip()
       else:
-        cached_hostname = socket.getfqdn()
+        cached_hostname = socket.getfqdn().lower()
     except:
-      cached_hostname = socket.getfqdn()
+      cached_hostname = socket.getfqdn().lower()
   except:
-    cached_hostname = socket.getfqdn()
+    cached_hostname = socket.getfqdn().lower()
   return cached_hostname
 
 
@@ -81,7 +81,7 @@ def public_hostname(config):
     handle.close()
     cached_public_hostname = str
   except Exception, e:
-    cached_public_hostname = socket.getfqdn()
+    cached_public_hostname = socket.getfqdn().lower()
   return cached_public_hostname
 
 def main(argv=None):

http://git-wip-us.apache.org/repos/asf/ambari/blob/8de3425f/ambari-agent/src/main/python/ambari_agent/main.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/main.py b/ambari-agent/src/main/python/ambari_agent/main.py
index 622e86f..e43d901 100644
--- a/ambari-agent/src/main/python/ambari_agent/main.py
+++ b/ambari-agent/src/main/python/ambari_agent/main.py
@@ -25,60 +25,45 @@ import sys
 import traceback
 import os
 import time
+import platform
 import ConfigParser
 import ProcessHelper
 from Controller import Controller
-from AmbariConfig import AmbariConfig
+import AmbariConfig
 from NetUtil import NetUtil
 from PingPortListener import PingPortListener
 import hostname
 from DataCleaner import DataCleaner
 import socket
-
 logger = logging.getLogger()
+
 formatstr = "%(levelname)s %(asctime)s %(filename)s:%(lineno)d - %(message)s"
 agentPid = os.getpid()
-config = AmbariConfig()
+config = AmbariConfig.AmbariConfig()
 configFile = config.CONFIG_FILE
 two_way_ssl_property = config.TWO_WAY_SSL_PROPERTY
 
-if 'AMBARI_LOG_DIR' in os.environ:
-  logfile = os.environ['AMBARI_LOG_DIR'] + "/ambari-agent.log"
-else:
-  logfile = "/var/log/ambari-agent/ambari-agent.log"
-
-def signal_handler(signum, frame):
-  #we want the handler to run only for the agent process and not
-  #for the children (e.g. namenode, etc.)
-  if os.getpid() != agentPid:
-    os._exit(0)
-  logger.info('signal received, exiting.')
-  ProcessHelper.stopAgent()
-
-def debug(sig, frame):
-  """Interrupt running process, and provide a python prompt for
-  interactive debugging."""
-  d={'_frame':frame}         # Allow access to frame object.
-  d.update(frame.f_globals)  # Unless shadowed by global
-  d.update(frame.f_locals)
-
-  message  = "Signal received : entering python shell.\nTraceback:\n"
-  message += ''.join(traceback.format_stack(frame))
-  logger.info(message)
+IS_WINDOWS = platform.system() == "Windows"
 
+if IS_WINDOWS:
+  from HeartbeatHandlers_windows import bind_signal_handlers
+else:
+  from HeartbeatStopHandler_linux import bind_signal_handlers
+  from HeartbeatStopHandler_linux import signal_handler
+  from HeartbeatStopHandler_linux import debug
 
 def setup_logging(verbose):
   formatter = logging.Formatter(formatstr)
-  rotateLog = logging.handlers.RotatingFileHandler(logfile, "a", 10000000, 25)
+  rotateLog = logging.handlers.RotatingFileHandler(AmbariConfig.AmbariConfig.getLogFile(), "a", 10000000, 25)
   rotateLog.setFormatter(formatter)
   logger.addHandler(rotateLog)
 
   if verbose:
-    logging.basicConfig(format=formatstr, level=logging.DEBUG, filename=logfile)
+    logging.basicConfig(format=formatstr, level=logging.DEBUG, filename=AmbariConfig.AmbariConfig.getLogFile())
     logger.setLevel(logging.DEBUG)
     logger.info("loglevel=logging.DEBUG")
   else:
-    logging.basicConfig(format=formatstr, level=logging.INFO, filename=logfile)
+    logging.basicConfig(format=formatstr, level=logging.INFO, filename=AmbariConfig.AmbariConfig.getLogFile())
     logger.setLevel(logging.INFO)
     logger.info("loglevel=logging.INFO")
 
@@ -89,35 +74,30 @@ def update_log_level(config):
     loglevel = config.get('agent', 'loglevel')
     if loglevel is not None:
       if loglevel == 'DEBUG':
-        logging.basicConfig(format=formatstr, level=logging.DEBUG, filename=logfile)
+        logging.basicConfig(format=formatstr, level=logging.DEBUG, filename=AmbariConfig.AmbariConfig.getLogFile())
         logger.setLevel(logging.DEBUG)
         logger.info("Newloglevel=logging.DEBUG")
       else:
-        logging.basicConfig(format=formatstr, level=logging.INFO, filename=logfile)
+        logging.basicConfig(format=formatstr, level=logging.INFO, filename=AmbariConfig.AmbariConfig.getLogFile())
         logger.setLevel(logging.INFO)
         logger.debug("Newloglevel=logging.INFO")
   except Exception, err:
     logger.info("Default loglevel=DEBUG")
 
 
-def bind_signal_handlers():
-  signal.signal(signal.SIGINT, signal_handler)
-  signal.signal(signal.SIGTERM, signal_handler)
-  signal.signal(signal.SIGUSR1, debug)
-
-
 #  ToDo: move that function inside AmbariConfig
 def resolve_ambari_config():
   global config
+  configPath = os.path.abspath(AmbariConfig.AmbariConfig.getConfigFile())
+
   try:
-    if os.path.exists(configFile):
-        config.read(configFile)
+    if os.path.exists(configPath):
+      config.read(configPath)
     else:
-      raise Exception("No config found, use default")
+      raise Exception("No config found at {0}, use default".format(configPath))
 
   except Exception, err:
     logger.warn(err)
-  return config
 
 
 def perform_prestart_checks(expected_hostname):
@@ -137,16 +117,21 @@ def perform_prestart_checks(expected_hostname):
       logger.error(msg)
       sys.exit(1)
   # Check if there is another instance running
-  if os.path.isfile(ProcessHelper.pidfile):
+  if os.path.isfile(ProcessHelper.pidfile) and not IS_WINDOWS:
     print("%s already exists, exiting" % ProcessHelper.pidfile)
     sys.exit(1)
   # check if ambari prefix exists
-  elif not os.path.isdir(config.get("agent", "prefix")):
+  elif config.has_option('agent', 'prefix') and not os.path.isdir(os.path.abspath(config.get('agent', 'prefix'))):
     msg = "Ambari prefix dir %s does not exists, can't continue" \
           % config.get("agent", "prefix")
     logger.error(msg)
     print(msg)
     sys.exit(1)
+  elif not config.has_option('agent', 'prefix'):
+    msg = "Ambari prefix dir %s not configured, can't continue"
+    logger.error(msg)
+    print(msg)
+    sys.exit(1)
 
 
 def daemonize():
@@ -207,7 +192,9 @@ def reset_agent(options):
 
   os._exit(0)
 
-def main():
+# event - event, that will be passed to Controller and NetUtil to make able to interrupt loops form outside process
+# we need this for windows os, where no sigterm available
+def main(heartbeat_stop_callback=None):
   global config
   parser = OptionParser()
   parser.add_option("-v", "--verbose", dest="verbose", action="store_true", help="verbose log output", default=False)
@@ -222,7 +209,7 @@ def main():
   default_cfg = {'agent': {'prefix': '/home/ambari'}}
   config.load(default_cfg)
 
-  bind_signal_handlers()
+  bind_signal_handlers(agentPid)
 
   if (len(sys.argv) > 1) and sys.argv[1] == 'stop':
     stop_agent()
@@ -231,16 +218,18 @@ def main():
     reset_agent(sys.argv)
 
   # Check for ambari configuration file.
-  config = resolve_ambari_config()
+  resolve_ambari_config()
 
   # Starting data cleanup daemon
   data_cleaner = None
-  if int(config.get('agent', 'data_cleanup_interval')) > 0:
+  if config.has_option('agent', 'data_cleanup_interval') and int(config.get('agent','data_cleanup_interval')) > 0:
     data_cleaner = DataCleaner(config)
     data_cleaner.start()
 
   perform_prestart_checks(expected_hostname)
-  daemonize()
+
+  if not IS_WINDOWS:
+    daemonize()
 
   # Starting ping port listener
   try:
@@ -264,15 +253,19 @@ def main():
     logger.warn("Unable to determine the IP address of the Ambari server '%s'", server_hostname)
 
   # Wait until server is reachable
-  netutil = NetUtil()
-  netutil.try_to_connect(server_url, -1, logger)
-
-  # Launch Controller communication
-  controller = Controller(config)
-  controller.start()
-  controller.join()
-  stop_agent()
+  netutil = NetUtil(heartbeat_stop_callback)
+  retries, connected = netutil.try_to_connect(server_url, -1, logger)
+  # Ambari Agent was stopped using stop event
+  if connected:
+    # Launch Controller communication
+    controller = Controller(config, heartbeat_stop_callback)
+    controller.start()
+    controller.join()
+  if not IS_WINDOWS:
+    stop_agent()
   logger.info("finished")
 
 if __name__ == "__main__":
-  main()
+  heartbeat_stop_callback = bind_signal_handlers(agentPid)
+
+  main(heartbeat_stop_callback)

http://git-wip-us.apache.org/repos/asf/ambari/blob/8de3425f/ambari-agent/src/main/python/ambari_agent/security.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/security.py b/ambari-agent/src/main/python/ambari_agent/security.py
index bc101b8..46eddca 100644
--- a/ambari-agent/src/main/python/ambari_agent/security.py
+++ b/ambari-agent/src/main/python/ambari_agent/security.py
@@ -27,12 +27,12 @@ import json
 import pprint
 import traceback
 import hostname
+import platform
 
 logger = logging.getLogger()
 
-GEN_AGENT_KEY = "openssl req -new -newkey rsa:1024 -nodes -keyout %(keysdir)s/%(hostname)s.key\
-  -subj /OU=%(hostname)s/\
-        -out %(keysdir)s/%(hostname)s.csr"
+GEN_AGENT_KEY = 'openssl req -new -newkey rsa:1024 -nodes -keyout "%(keysdir)s'+os.sep+'%(hostname)s.key" '\
+	'-subj /OU=%(hostname)s/ -out "%(keysdir)s'+os.sep+'%(hostname)s.csr"'
 
 
 class VerifiedHTTPSConnection(httplib.HTTPSConnection):
@@ -141,30 +141,30 @@ class CachedHTTPSConnection:
 class CertificateManager():
   def __init__(self, config):
     self.config = config
-    self.keysdir = self.config.get('security', 'keysdir')
+    self.keysdir = os.path.abspath(self.config.get('security', 'keysdir'))
     self.server_crt = self.config.get('security', 'server_crt')
     self.server_url = 'https://' + self.config.get('server', 'hostname') + ':' \
        + self.config.get('server', 'url_port')
 
   def getAgentKeyName(self):
-    keysdir = self.config.get('security', 'keysdir')
+    keysdir = os.path.abspath(self.config.get('security', 'keysdir'))
     return keysdir + os.sep + hostname.hostname(self.config) + ".key"
 
   def getAgentCrtName(self):
-    keysdir = self.config.get('security', 'keysdir')
+    keysdir = os.path.abspath(self.config.get('security', 'keysdir'))
     return keysdir + os.sep + hostname.hostname(self.config) + ".crt"
 
   def getAgentCrtReqName(self):
-    keysdir = self.config.get('security', 'keysdir')
+    keysdir = os.path.abspath(self.config.get('security', 'keysdir'))
     return keysdir + os.sep + hostname.hostname(self.config) + ".csr"
 
   def getSrvrCrtName(self):
-    keysdir = self.config.get('security', 'keysdir')
+    keysdir = os.path.abspath(self.config.get('security', 'keysdir'))
     return keysdir + os.sep + "ca.crt"
 
   def checkCertExists(self):
 
-    s = self.config.get('security', 'keysdir') + os.sep + "ca.crt"
+    s = os.path.abspath(self.config.get('security', 'keysdir')) + os.sep + "ca.crt"
 
     server_crt_exists = os.path.exists(s)
 
@@ -240,10 +240,14 @@ class CertificateManager():
 
   def genAgentCrtReq(self):
     generate_script = GEN_AGENT_KEY % {'hostname': hostname.hostname(self.config),
-                                     'keysdir': self.config.get('security', 'keysdir')}
+                                     'keysdir' : os.path.abspath(self.config.get('security', 'keysdir'))}
     logger.info(generate_script)
-    p = subprocess.Popen([generate_script], shell=True, stdout=subprocess.PIPE)
-    p.communicate()
+    if platform.system() == 'Windows':
+      p = subprocess.Popen(generate_script, stdout=subprocess.PIPE)
+      p.communicate()
+    else:
+      p = subprocess.Popen([generate_script], shell=True, stdout=subprocess.PIPE)
+      p.communicate()
 
   def initSecurity(self):
     self.checkCertExists()

http://git-wip-us.apache.org/repos/asf/ambari/blob/8de3425f/ambari-agent/src/main/python/ambari_agent/shell.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/shell.py b/ambari-agent/src/main/python/ambari_agent/shell.py
index 4081bb0..df6f0ca 100644
--- a/ambari-agent/src/main/python/ambari_agent/shell.py
+++ b/ambari-agent/src/main/python/ambari_agent/shell.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+# !/usr/bin/env python
 
 '''
 Licensed to the Apache Software Foundation (ASF) under one
@@ -29,26 +29,79 @@ import time
 import traceback
 import AmbariConfig
 import pprint
+import platform
 
-try:
+if platform.system() != "Windows":
+  try:
     import pwd
-except ImportError:
+  except ImportError:
     import winpwd as pwd
 
-global serverTracker
-serverTracker = {}
 logger = logging.getLogger()
 
+shellRunner = None
 threadLocal = threading.local()
-gracefull_kill_delay = 5 # seconds between SIGTERM and SIGKILL
-tempFiles = [] 
+gracefull_kill_delay = 5  # seconds between SIGTERM and SIGKILL
+
+tempFiles = []
+
+
 def noteTempFile(filename):
   tempFiles.append(filename)
 
+
 def getTempFiles():
   return tempFiles
 
-def kill_process_with_children(parent_pid):
+
+class _dict_to_object:
+  def __init__(self, entries):
+    self.__dict__.update(entries)
+
+  def __getitem__(self, item):
+    return self.__dict__[item]
+
+
+# windows specific code
+def _kill_process_with_children_windows(parent_pid):
+  shellRunner().run(["taskkill", "/T", "/PID", "{0}".format(parent_pid)])
+
+
+class shellRunnerWindows:
+  # Run any command
+  def run(self, script, user=None):
+    logger.warn("user argument ignored on windows")
+    code = 0
+    if not isinstance(script, list):
+      cmd = " "
+      cmd = cmd.join(script)
+    else:
+      cmd = script
+    p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
+                         stderr=subprocess.PIPE, shell=False)
+    out, err = p.communicate()
+    code = p.wait()
+    logger.debug("Exitcode for %s is %d" % (cmd, code))
+    return {'exitCode': code, 'output': out, 'error': err}
+
+  def runPowershell(self, file=None, script_block=None, args=[]):
+    logger.warn("user argument ignored on windows")
+    code = 0
+    cmd = None
+    if file:
+      cmd = ['powershell', '-WindowStyle', 'Hidden', '-File', file] + args
+    elif script_block:
+      cmd = ['powershell', '-WindowStyle', 'Hidden', '-Command', script_block] + args
+    p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
+                         stderr=subprocess.PIPE, shell=False)
+    out, err = p.communicate()
+    code = p.wait()
+    logger.debug("Exitcode for %s is %d" % (cmd, code))
+    return _dict_to_object({'exitCode': code, 'output': out, 'error': err})
+
+
+#linux specific code
+def _kill_process_with_children_linux(parent_pid):
   def kill_tree_function(pid, signal):
     '''
     Kills process tree starting from a given pid.
@@ -58,15 +111,17 @@ def kill_process_with_children(parent_pid):
     # a given PID and then passes list of "kill -<SIGNAL> PID" commands to 'sh'
     # shell.
     CMD = """ps xf | awk -v PID=""" + str(pid) + \
-        """ ' $1 == PID { P = $1; next } P && /_/ { P = P " " $1;""" + \
-        """K=P } P && !/_/ { P="" }  END { print "kill -""" \
-        + str(signal) + """ "K }' | sh """
+          """ ' $1 == PID { P = $1; next } P && /_/ { P = P " " $1;""" + \
+          """K=P } P && !/_/ { P="" }  END { print "kill -""" \
+          + str(signal) + """ "K }' | sh """
     process = subprocess.Popen(CMD, stdout=subprocess.PIPE,
                                stderr=subprocess.PIPE, shell=True)
     process.communicate()
-  run_kill_function(kill_tree_function, parent_pid)
 
-def run_kill_function(kill_function, pid):
+  _run_kill_function(kill_tree_function, parent_pid)
+
+
+def _run_kill_function(kill_function, pid):
   try:
     kill_function(pid, signal.SIGTERM)
   except Exception, e:
@@ -81,17 +136,19 @@ def run_kill_function(kill_function, pid):
     logger.error("Failed to send SIGKILL to PID %d. Process exited?" % (pid))
     logger.error("Reported error: " + repr(e))
 
-def changeUid():
+
+def _changeUid():
   try:
     os.setuid(threadLocal.uid)
   except Exception:
     logger.warn("can not switch user for running command.")
 
-class shellRunner:
+
+class shellRunnerLinux:
   # Run any command
   def run(self, script, user=None):
     try:
-      if user!=None:
+      if user != None:
         user = pwd.getpwnam(user)[2]
       else:
         user = os.getuid()
@@ -101,12 +158,28 @@ class shellRunner:
     code = 0
     cmd = " "
     cmd = cmd.join(script)
-    p = subprocess.Popen(cmd, preexec_fn=changeUid, stdout=subprocess.PIPE, 
+    p = subprocess.Popen(cmd, preexec_fn=_changeUid, stdout=subprocess.PIPE,
                          stderr=subprocess.PIPE, shell=True, close_fds=True)
     out, err = p.communicate()
     code = p.wait()
-    logger.debug("Exitcode for %s is %d" % (cmd,code))
+    logger.debug("Exitcode for %s is %d" % (cmd, code))
     return {'exitCode': code, 'output': out, 'error': err}
 
-  def getServerTracker(self):
-    return serverTracker
\ No newline at end of file
+
+def kill_process_with_children(parent_pid):
+  if platform.system() == "Windows":
+    _kill_process_with_children_windows(parent_pid)
+  else:
+    _kill_process_with_children_linux(parent_pid)
+
+def changeUid():
+  if not platform.system() == "Windows":
+    try:
+      os.setuid(threadLocal.uid)
+    except Exception:
+      logger.warn("can not switch user for running command.")
+
+if platform.system() == "Windows":
+  shellRunner = shellRunnerWindows
+else:
+  shellRunner = shellRunnerLinux
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/8de3425f/ambari-agent/src/packages/windows.xml
----------------------------------------------------------------------
diff --git a/ambari-agent/src/packages/windows.xml b/ambari-agent/src/packages/windows.xml
new file mode 100644
index 0000000..1abca20
--- /dev/null
+++ b/ambari-agent/src/packages/windows.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0"?>
+<!--
+   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.
+-->
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.1"
+          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+          xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.1 http://maven.apache.org/xsd/assembly-1.1.1.xsd">
+  <!--This 'all' id is not appended to the produced bundle because we do this:
+    http://maven.apache.org/plugins/maven-assembly-plugin/faq.html#required-classifiers
+  -->
+  <id>windows-dist</id>
+  <formats>
+    <format>dir</format>
+  </formats>
+  <includeBaseDirectory>false</includeBaseDirectory>
+  <fileSets>
+    <fileSet>
+      <directory>src/main/python/ambari_agent</directory>
+      <outputDirectory>/sbin/ambari_agent</outputDirectory>
+    </fileSet>
+    <fileSet>
+      <directory>${project.basedir}/../ambari-common/src/main/python/resource_management</directory>
+      <outputDirectory>/sbin/resource_management</outputDirectory>
+    </fileSet>
+    <fileSet>
+      <directory>${project.basedir}/../ambari-common/src/main/python/ambari_commons</directory>
+      <outputDirectory>/sbin/ambari_commons</outputDirectory>
+    </fileSet>
+    <fileSet>
+      <directory>${project.basedir}/../ambari-common/src/main/python/ambari_jinja2/ambari_jinja2</directory>
+      <outputDirectory>/sbin/ambari_jinja2</outputDirectory>
+    </fileSet>
+    <fileSet>
+      <directory>${project.basedir}/conf/windows</directory>
+      <outputDirectory>/</outputDirectory>
+      <excludes>
+        <exclude>service_wrapper.py</exclude>
+        <exclude>createservice.ps1</exclude>
+      </excludes>
+    </fileSet>
+    <fileSet>
+      <directory>${project.basedir}/conf/windows</directory>
+      <outputDirectory>/sbin</outputDirectory>
+      <includes>
+        <include>service_wrapper.py</include>
+        <include>createservice.ps1</include>
+      </includes>
+    </fileSet>
+    <fileSet>
+      <directory>${target.cache.dir}</directory>
+      <outputDirectory>/cache</outputDirectory>
+    </fileSet>
+    <!--empty directory-->
+    <fileSet>
+      <directory>./</directory>
+      <outputDirectory>/keys</outputDirectory>
+      <excludes>
+        <exclude>*/**</exclude>
+      </excludes>
+    </fileSet>
+  </fileSets>
+  <files>
+    <file>
+      <source>${project.basedir}/../version</source>
+      <outputDirectory>data</outputDirectory>
+      <filtered>true</filtered>
+    </file>
+  </files>
+</assembly>

http://git-wip-us.apache.org/repos/asf/ambari/blob/8de3425f/ambari-agent/src/test/python/ambari_agent/TestAlerts.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/test/python/ambari_agent/TestAlerts.py b/ambari-agent/src/test/python/ambari_agent/TestAlerts.py
index 9bbcf3b..d3e4583 100644
--- a/ambari-agent/src/test/python/ambari_agent/TestAlerts.py
+++ b/ambari-agent/src/test/python/ambari_agent/TestAlerts.py
@@ -18,9 +18,10 @@ See the License for the specific language governing permissions and
 limitations under the License.
 '''
 
+from stacks.utils.RMFTestCase import *
+import os
 import socket
 import sys
-import os
 
 from ambari_agent.AlertSchedulerHandler import AlertSchedulerHandler
 from ambari_agent.alerts.collector import AlertCollector
@@ -429,12 +430,12 @@ class TestAlerts(TestCase):
     
     ash = AlertSchedulerHandler(test_file_path, test_stack_path, test_host_scripts_path)
     ash.start()
-    
+
     self.assertEquals(1, ash.get_job_count())
     ash.reschedule()
     self.assertEquals(1, ash.get_job_count())
-        
-  
+
+
   def test_alert_collector_purge(self):
     json = { "name": "namenode_process",
       "service": "HDFS",
@@ -466,13 +467,13 @@ class TestAlerts(TestCase):
     self.assertEquals(6, pa.interval())
 
     res = pa.collect()
-    
+
     self.assertTrue(collector.alerts()[0] is not None)
     self.assertEquals('CRITICAL', collector.alerts()[0]['state'])
-    
+
     collector.remove_by_uuid('c1f73191-4481-4435-8dae-fd380e4c0be1')
     self.assertEquals(0,len(collector.alerts()))
-    
+
 
   def test_disabled_definitions(self):
     test_file_path = os.path.join('ambari_agent', 'dummy_files')
@@ -509,24 +510,23 @@ class TestAlerts(TestCase):
 
     pa = PortAlert(json, json['source'])
     ash.schedule_definition(pa)
-    
+
     self.assertEquals(2, ash.get_job_count())
-    
+
     json['enabled'] = False
     pa = PortAlert(json, json['source'])
     ash.schedule_definition(pa)
-    
+
     # verify disabled alert not scheduled
     self.assertEquals(2, ash.get_job_count())
-    
+
     json['enabled'] = True
     pa = PortAlert(json, json['source'])
     ash.schedule_definition(pa)
-    
+
     # verify enabled alert was scheduled
     self.assertEquals(3, ash.get_job_count())
 
-
   def test_immediate_alert(self):
     test_file_path = os.path.join('ambari_agent', 'dummy_files')
     test_stack_path = os.path.join('ambari_agent', 'dummy_files')
@@ -538,10 +538,10 @@ class TestAlerts(TestCase):
     self.assertEquals(1, ash.get_job_count())
     self.assertEquals(0, len(ash._collector.alerts()))
 
-    execution_commands = [ { 
+    execution_commands = [ {
         "clusterName": "c1",
-        "hostName": "c6401.ambari.apache.org",    
-        "alertDefinition": {         
+        "hostName": "c6401.ambari.apache.org",
+        "alertDefinition": {
           "name": "namenode_process",
           "service": "HDFS",
           "component": "NAMENODE",
@@ -565,7 +565,7 @@ class TestAlerts(TestCase):
           }
         }
       } ]
-    
+
     # execute the alert immediately and verify that the collector has the result
     ash.execute_alert(execution_commands)
     self.assertEquals(1, len(ash._collector.alerts()))

http://git-wip-us.apache.org/repos/asf/ambari/blob/8de3425f/ambari-agent/src/test/python/ambari_agent/TestCertGeneration.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/test/python/ambari_agent/TestCertGeneration.py b/ambari-agent/src/test/python/ambari_agent/TestCertGeneration.py
index 8e01707..c724c31 100644
--- a/ambari-agent/src/test/python/ambari_agent/TestCertGeneration.py
+++ b/ambari-agent/src/test/python/ambari_agent/TestCertGeneration.py
@@ -45,4 +45,3 @@ class TestCertGeneration(TestCase):
   def tearDown(self):
     shutil.rmtree(self.tmpdir)
 
-

http://git-wip-us.apache.org/repos/asf/ambari/blob/8de3425f/ambari-agent/src/test/python/ambari_agent/TestController.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/test/python/ambari_agent/TestController.py b/ambari-agent/src/test/python/ambari_agent/TestController.py
index 72b0cea..240d808 100644
--- a/ambari-agent/src/test/python/ambari_agent/TestController.py
+++ b/ambari-agent/src/test/python/ambari_agent/TestController.py
@@ -385,7 +385,7 @@ class TestController(unittest.TestCase):
 
     hearbeat = MagicMock()
     self.controller.heartbeat = hearbeat
-
+    event_mock.return_value = False
     dumpsMock.return_value = "data"
 
     sendRequest = MagicMock(name="sendRequest")
@@ -512,7 +512,7 @@ class TestController(unittest.TestCase):
     response["restartAgent"] = "false"
     self.controller.heartbeatWithServer()
 
-    sleepMock.assert_called_with(
+    event_mock.assert_any_call(timeout=
       self.controller.netutil.MINIMUM_INTERVAL_BETWEEN_HEARTBEATS)
 
     # Check that server continues to heartbeat after connection errors
@@ -533,7 +533,7 @@ class TestController(unittest.TestCase):
     self.controller.heartbeatWithServer()
     self.assertTrue(sendRequest.call_count > 5)
 
-    sleepMock.assert_called_with(
+    event_mock.assert_called_with(timeout=
       self.controller.netutil.MINIMUM_INTERVAL_BETWEEN_HEARTBEATS)
 
     sys.stdout = sys.__stdout__

http://git-wip-us.apache.org/repos/asf/ambari/blob/8de3425f/ambari-agent/src/test/python/ambari_agent/TestCustomServiceOrchestrator.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/test/python/ambari_agent/TestCustomServiceOrchestrator.py b/ambari-agent/src/test/python/ambari_agent/TestCustomServiceOrchestrator.py
index 5f426e6..24ee259 100644
--- a/ambari-agent/src/test/python/ambari_agent/TestCustomServiceOrchestrator.py
+++ b/ambari-agent/src/test/python/ambari_agent/TestCustomServiceOrchestrator.py
@@ -95,7 +95,8 @@ class TestCustomServiceOrchestrator(TestCase):
       'clusterHostInfo':{'namenode_host' : ['1'],
                          'slave_hosts'   : ['0', '1'],
                          'all_hosts'     : ['h1.hortonworks.com', 'h2.hortonworks.com'],
-                         'all_ping_ports': ['8670:0,1']}
+                         'all_ping_ports': ['8670:0,1']},
+      'hostLevelParams':{}
     }
     
     decompress_cluster_host_info_mock.return_value = {'namenode_host' : ['h2.hortonworks.com'],
@@ -315,15 +316,15 @@ class TestCustomServiceOrchestrator(TestCase):
     self.assertTrue(os.path.exists(err))
     os.remove(out)
     os.remove(err)
-    
+
   from ambari_agent.StackVersionsFileHandler import StackVersionsFileHandler
-    
+
   @patch("shell.kill_process_with_children")
   @patch.object(FileCache, "__init__")
   @patch.object(CustomServiceOrchestrator, "resolve_script_path")
   @patch.object(CustomServiceOrchestrator, "resolve_hook_script_path")
   @patch.object(StackVersionsFileHandler, "read_stack_version")
-  def test_cancel_backgound_command(self, read_stack_version_mock, resolve_hook_script_path_mock, resolve_script_path_mock, FileCache_mock,  
+  def test_cancel_backgound_command(self, read_stack_version_mock, resolve_hook_script_path_mock, resolve_script_path_mock, FileCache_mock,
                                       kill_process_with_children_mock):
     FileCache_mock.return_value = None
     FileCache_mock.cache_dir = MagicMock()
@@ -334,9 +335,9 @@ class TestCustomServiceOrchestrator(TestCase):
     cfg.set('agent', 'tolerate_download_failures', 'true')
     cfg.set('agent', 'prefix', '.')
     cfg.set('agent', 'cache_dir', 'background_tasks')
-     
+
     actionQueue = ActionQueue(cfg, dummy_controller)
-    
+
     dummy_controller.actionQueue = actionQueue
     orchestrator = CustomServiceOrchestrator(cfg, dummy_controller)
     orchestrator.file_cache = MagicMock()
@@ -344,42 +345,42 @@ class TestCustomServiceOrchestrator(TestCase):
       return ""
     orchestrator.file_cache.get_service_base_dir = f
     actionQueue.customServiceOrchestrator = orchestrator
-    
+
     import TestActionQueue
     import copy
-    
+
     TestActionQueue.patch_output_file(orchestrator.python_executor)
     orchestrator.python_executor.prepare_process_result = MagicMock()
     orchestrator.dump_command_to_json = MagicMock()
- 
+
     lock = threading.RLock()
     complete_done = threading.Condition(lock)
-    
+
     complete_was_called = {}
     def command_complete_w(process_condenced_result, handle):
       with lock:
         complete_was_called['visited']= ''
         complete_done.wait(3)
-     
-    actionQueue.on_background_command_complete_callback = TestActionQueue.wraped(actionQueue.on_background_command_complete_callback, command_complete_w, None) 
+
+    actionQueue.on_background_command_complete_callback = TestActionQueue.wraped(actionQueue.on_background_command_complete_callback, command_complete_w, None)
     execute_command = copy.deepcopy(TestActionQueue.TestActionQueue.background_command)
     actionQueue.put([execute_command])
     actionQueue.processBackgroundQueueSafeEmpty()
-     
-    time.sleep(.1) 
-    
+
+    time.sleep(.1)
+
     orchestrator.cancel_command(19,'')
     self.assertTrue(kill_process_with_children_mock.called)
     kill_process_with_children_mock.assert_called_with(33)
-     
+
     with lock:
       complete_done.notifyAll()
 
     with lock:
       self.assertTrue(complete_was_called.has_key('visited'))
-    
+
     time.sleep(.1)
-     
+
     runningCommand = actionQueue.commandStatuses.get_command_status(19)
     self.assertTrue(runningCommand is not None)
     self.assertEqual(runningCommand['status'], ActionQueue.FAILED_STATUS)
@@ -501,12 +502,12 @@ class TestCustomServiceOrchestrator(TestCase):
     }
     dummy_controller = MagicMock()
     orchestrator = CustomServiceOrchestrator(self.config, dummy_controller)
-    
+
     import TestActionQueue
     TestActionQueue.patch_output_file(orchestrator.python_executor)
     orchestrator.python_executor.condenseOutput = MagicMock()
     orchestrator.dump_command_to_json = MagicMock()
-    
+
     ret = orchestrator.runCommand(command, "out.txt", "err.txt")
     self.assertEqual(ret['exitcode'], 777)
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/8de3425f/ambari-agent/src/test/python/ambari_agent/TestHostname.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/test/python/ambari_agent/TestHostname.py b/ambari-agent/src/test/python/ambari_agent/TestHostname.py
index 7d1f3c6..993a9d1 100644
--- a/ambari-agent/src/test/python/ambari_agent/TestHostname.py
+++ b/ambari-agent/src/test/python/ambari_agent/TestHostname.py
@@ -34,7 +34,7 @@ class TestHostname(TestCase):
     hostname.cached_hostname = None
     hostname.cached_public_hostname = None
     config = AmbariConfig()
-    self.assertEquals(hostname.hostname(config), socket.getfqdn(),
+    self.assertEquals(hostname.hostname(config), socket.getfqdn().lower(),
                       "hostname should equal the socket-based hostname")
     pass
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/8de3425f/ambari-agent/src/test/python/ambari_agent/TestMain.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/test/python/ambari_agent/TestMain.py b/ambari-agent/src/test/python/ambari_agent/TestMain.py
index f930c4a..bb75bac 100644
--- a/ambari-agent/src/test/python/ambari_agent/TestMain.py
+++ b/ambari-agent/src/test/python/ambari_agent/TestMain.py
@@ -52,23 +52,22 @@ class TestMain(unittest.TestCase):
     sys.stdout = sys.__stdout__
 
 
+  @patch("ambari_agent.HeartbeatStopHandler_linux")
   @patch("os._exit")
   @patch("os.getpid")
   @patch.object(ProcessHelper, "stopAgent")
-  def test_signal_handler(self, stopAgent_mock, os_getpid_mock, os_exit_mock):
+  def test_signal_handler(self, stopAgent_mock, os_getpid_mock, os_exit_mock, heartbeat_handler_mock):
     # testing exit of children
     main.agentPid = 4444
     os_getpid_mock.return_value = 5555
     main.signal_handler("signum", "frame")
-    self.assertTrue(os_exit_mock.called)
-
+    heartbeat_handler_mock.set_stop.assert_called()
     os_exit_mock.reset_mock()
 
     # testing exit of main process
     os_getpid_mock.return_value = main.agentPid
     main.signal_handler("signum", "frame")
-    self.assertFalse(os_exit_mock.called)
-    self.assertTrue(stopAgent_mock.called)
+    heartbeat_handler_mock.set_stop.assert_called()
 
 
   @patch.object(main.logger, "addHandler")
@@ -122,7 +121,7 @@ class TestMain(unittest.TestCase):
 
   @patch("signal.signal")
   def test_bind_signal_handlers(self, signal_mock):
-    main.bind_signal_handlers()
+    main.bind_signal_handlers(os.getpid())
     # Check if on SIGINT/SIGTERM agent is configured to terminate
     signal_mock.assert_any_call(signal.SIGINT, main.signal_handler)
     signal_mock.assert_any_call(signal.SIGTERM, main.signal_handler)
@@ -269,7 +268,7 @@ class TestMain(unittest.TestCase):
   @patch.object(main, "setup_logging")
   @patch.object(main, "bind_signal_handlers")
   @patch.object(main, "stop_agent")
-  @patch.object(main, "resolve_ambari_config")
+  @patch.object(AmbariConfig, "getConfigFile")
   @patch.object(main, "perform_prestart_checks")
   @patch.object(main, "daemonize")
   @patch.object(main, "update_log_level")
@@ -285,21 +284,25 @@ class TestMain(unittest.TestCase):
   def test_main(self, ping_port_init_mock, ping_port_start_mock, data_clean_init_mock,data_clean_start_mock,
                 parse_args_mock, join_mock, start_mock, Controller_init_mock, try_to_connect_mock,
                 update_log_level_mock, daemonize_mock, perform_prestart_checks_mock,
-                resolve_ambari_config_mock, stop_mock, bind_signal_handlers_mock,
+                ambari_config_mock,
+                stop_mock, bind_signal_handlers_mock,
                 setup_logging_mock, socket_mock):
     data_clean_init_mock.return_value = None
     Controller_init_mock.return_value = None
     ping_port_init_mock.return_value = None
     options = MagicMock()
     parse_args_mock.return_value = (options, MagicMock)
-
+    try_to_connect_mock.return_value = (0, True)
+    # use default unix config
+    ambari_config_mock.return_value = os.path.abspath("../../../conf/unix/ambari-agent.ini")
     #testing call without command-line arguments
+
     main.main()
 
     self.assertTrue(setup_logging_mock.called)
     self.assertTrue(bind_signal_handlers_mock.called)
     self.assertTrue(stop_mock.called)
-    self.assertTrue(resolve_ambari_config_mock.called)
+    #self.assertTrue(resolve_ambari_config_mock.called)
     self.assertTrue(perform_prestart_checks_mock.called)
     self.assertTrue(daemonize_mock.called)
     self.assertTrue(update_log_level_mock.called)

http://git-wip-us.apache.org/repos/asf/ambari/blob/8de3425f/ambari-agent/src/test/python/ambari_agent/TestNetUtil.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/test/python/ambari_agent/TestNetUtil.py b/ambari-agent/src/test/python/ambari_agent/TestNetUtil.py
index 474548f..255da88 100644
--- a/ambari-agent/src/test/python/ambari_agent/TestNetUtil.py
+++ b/ambari-agent/src/test/python/ambari_agent/TestNetUtil.py
@@ -21,6 +21,7 @@ limitations under the License.
 from ambari_agent import NetUtil
 from mock.mock import MagicMock, patch
 import unittest
+import threading
 
 class TestNetUtil(unittest.TestCase):
 
@@ -51,15 +52,17 @@ class TestNetUtil(unittest.TestCase):
 
 
   @patch("time.sleep")
-  def test_try_to_connect(self, sleepMock):
-
+  @patch.object(threading._Event, "wait")
+  def test_try_to_connect(self, event_mock,
+                            sleepMock):
+    event_mock.return_value = False
     netutil = NetUtil.NetUtil()
     checkURL = MagicMock(name="checkURL")
     checkURL.return_value = True, "test"
     netutil.checkURL = checkURL
 
     # one successful get
-    self.assertEqual(0, netutil.try_to_connect("url", 10))
+    self.assertEqual((0, True), netutil.try_to_connect("url", 10))
 
     # got successful after N retries
     gets = [[True, ""], [False, ""], [False, ""]]
@@ -67,9 +70,9 @@ class TestNetUtil(unittest.TestCase):
     def side_effect(*args):
       return gets.pop()
     checkURL.side_effect = side_effect
-    self.assertEqual(2, netutil.try_to_connect("url", 10))
+    self.assertEqual((2, True), netutil.try_to_connect("url", 10))
 
     # max retries
     checkURL.side_effect = None
     checkURL.return_value = False, "test"
-    self.assertEqual(5, netutil.try_to_connect("url", 5))
+    self.assertEqual((5,False), netutil.try_to_connect("url", 5))

http://git-wip-us.apache.org/repos/asf/ambari/blob/8de3425f/ambari-agent/src/test/python/ambari_agent/TestStatusCheck.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/test/python/ambari_agent/TestStatusCheck.py b/ambari-agent/src/test/python/ambari_agent/TestStatusCheck.py
index 50657d8..a872e7f 100644
--- a/ambari-agent/src/test/python/ambari_agent/TestStatusCheck.py
+++ b/ambari-agent/src/test/python/ambari_agent/TestStatusCheck.py
@@ -47,7 +47,7 @@ class TestStatusCheck(TestCase):
 
   def setUp(self):
 
-    self.pidPathesVars = [
+    self.pidPathVars = [
       {'var' : '',
       'defaultValue' : PID_DIR}
     ]
@@ -84,7 +84,7 @@ class TestStatusCheck(TestCase):
   @patch.object(StatusCheck, 'getIsLive')
   def test_live(self, get_is_live_mock):
 
-    statusCheck = StatusCheck(self.serviceToPidDict, self.pidPathesVars,
+    statusCheck = StatusCheck(self.serviceToPidDict, self.pidPathVars,
       self.globalConfig, self.servicesToLinuxUser)
 
     self.assertTrue(StatusCheck.USER_PATTERN in self.serviceToPidDict[COMPONENT_LIVE])
@@ -108,11 +108,11 @@ class TestStatusCheck(TestCase):
     logger_info_mock.side_effect = my_side_effect
     
     # call this three times
-    statusCheck = StatusCheck(self.serviceToPidDict, self.pidPathesVars,
+    statusCheck = StatusCheck(self.serviceToPidDict, self.pidPathVars,
       self.globalConfig, self.servicesToLinuxUser)
-    statusCheck = StatusCheck(self.serviceToPidDict, self.pidPathesVars,
+    statusCheck = StatusCheck(self.serviceToPidDict, self.pidPathVars,
       self.globalConfig, self.servicesToLinuxUser)
-    statusCheck = StatusCheck(self.serviceToPidDict, self.pidPathesVars,
+    statusCheck = StatusCheck(self.serviceToPidDict, self.pidPathVars,
       self.globalConfig, self.servicesToLinuxUser)
     # logged not more then once
     self.assert_(TestStatusCheck.timesLogged <= 1, "test_dont_relog_serToPidDict logged more then once")
@@ -129,7 +129,7 @@ class TestStatusCheck(TestCase):
     self.pidFilesDict[one_more_pid_file_name] = one_more_pid_full_path
     self.is_live_values[one_more_pid_full_path] = False
 
-    statusCheck = StatusCheck(self.serviceToPidDict, self.pidPathesVars,
+    statusCheck = StatusCheck(self.serviceToPidDict, self.pidPathVars,
       self.globalConfig, self.servicesToLinuxUser)
 
     statusCheck.pidFilesDict = self.pidFilesDict
@@ -149,7 +149,7 @@ class TestStatusCheck(TestCase):
     badServiceToPidDict = self.serviceToPidDict.copy()
     badServiceToPidDict['BAD_COMPONENT'] = 'prefix' + StatusCheck.USER_PATTERN
 
-    statusCheck = StatusCheck(badServiceToPidDict, self.pidPathesVars,
+    statusCheck = StatusCheck(badServiceToPidDict, self.pidPathVars,
       self.globalConfig, self.servicesToLinuxUser)
 
     statusCheck.pidFilesDict = self.pidFilesDict
@@ -162,7 +162,7 @@ class TestStatusCheck(TestCase):
   # Ensure that status checker return False for dead process
   @patch.object(StatusCheck, 'getIsLive')
   def test_dead(self, get_is_live_mock):
-    statusCheck = StatusCheck(self.serviceToPidDict, self.pidPathesVars,
+    statusCheck = StatusCheck(self.serviceToPidDict, self.pidPathVars,
       self.globalConfig, self.servicesToLinuxUser)
 
     statusCheck.pidFilesDict = self.pidFilesDict

http://git-wip-us.apache.org/repos/asf/ambari/blob/8de3425f/ambari-agent/src/test/python/resource_management/TestContentSources.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/test/python/resource_management/TestContentSources.py b/ambari-agent/src/test/python/resource_management/TestContentSources.py
index 1c5e8a8..d09df44 100644
--- a/ambari-agent/src/test/python/resource_management/TestContentSources.py
+++ b/ambari-agent/src/test/python/resource_management/TestContentSources.py
@@ -16,7 +16,7 @@ See the License for the specific language governing permissions and
 limitations under the License.
 '''
 
-
+from stacks.utils.RMFTestCase import *
 from unittest import TestCase
 from mock.mock import patch, MagicMock
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/8de3425f/ambari-agent/src/test/python/resource_management/TestDirectoryResource.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/test/python/resource_management/TestDirectoryResource.py b/ambari-agent/src/test/python/resource_management/TestDirectoryResource.py
index 866486e..5a63891 100644
--- a/ambari-agent/src/test/python/resource_management/TestDirectoryResource.py
+++ b/ambari-agent/src/test/python/resource_management/TestDirectoryResource.py
@@ -16,7 +16,7 @@ See the License for the specific language governing permissions and
 limitations under the License.
 '''
 
-
+from stacks.utils.RMFTestCase import *
 from unittest import TestCase
 from mock.mock import patch, MagicMock
 import os

http://git-wip-us.apache.org/repos/asf/ambari/blob/8de3425f/ambari-agent/src/test/python/resource_management/TestExecuteHadoopResource.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/test/python/resource_management/TestExecuteHadoopResource.py b/ambari-agent/src/test/python/resource_management/TestExecuteHadoopResource.py
index d2ef71c..f5308d1 100644
--- a/ambari-agent/src/test/python/resource_management/TestExecuteHadoopResource.py
+++ b/ambari-agent/src/test/python/resource_management/TestExecuteHadoopResource.py
@@ -15,6 +15,8 @@ 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.
 '''
+
+from stacks.utils.RMFTestCase import *
 import os
 
 from unittest import TestCase

http://git-wip-us.apache.org/repos/asf/ambari/blob/8de3425f/ambari-agent/src/test/python/resource_management/TestExecuteResource.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/test/python/resource_management/TestExecuteResource.py b/ambari-agent/src/test/python/resource_management/TestExecuteResource.py
index f974b92..8423eec 100644
--- a/ambari-agent/src/test/python/resource_management/TestExecuteResource.py
+++ b/ambari-agent/src/test/python/resource_management/TestExecuteResource.py
@@ -16,6 +16,7 @@ See the License for the specific language governing permissions and
 limitations under the License.
 '''
 
+from stacks.utils.RMFTestCase import *
 from unittest import TestCase
 from mock.mock import patch, MagicMock, call
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/8de3425f/ambari-agent/src/test/python/resource_management/TestMonitorWebserverResource.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/test/python/resource_management/TestMonitorWebserverResource.py b/ambari-agent/src/test/python/resource_management/TestMonitorWebserverResource.py
index 533ecaa..d5b2c42 100644
--- a/ambari-agent/src/test/python/resource_management/TestMonitorWebserverResource.py
+++ b/ambari-agent/src/test/python/resource_management/TestMonitorWebserverResource.py
@@ -16,6 +16,7 @@ See the License for the specific language governing permissions and
 limitations under the License.
 '''
 
+from stacks.utils.RMFTestCase import *
 from unittest import TestCase
 from mock.mock import patch, MagicMock
 from resource_management import *

http://git-wip-us.apache.org/repos/asf/ambari/blob/8de3425f/ambari-agent/src/test/python/resource_management/TestSubstituteVars.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/test/python/resource_management/TestSubstituteVars.py b/ambari-agent/src/test/python/resource_management/TestSubstituteVars.py
index b3623cd..9e42f92 100644
--- a/ambari-agent/src/test/python/resource_management/TestSubstituteVars.py
+++ b/ambari-agent/src/test/python/resource_management/TestSubstituteVars.py
@@ -17,6 +17,8 @@ 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.
 '''
+
+from stacks.utils.RMFTestCase import *
 from unittest import TestCase, main
 from resource_management.libraries.functions.substitute_vars import substitute_vars
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/8de3425f/ambari-agent/src/test/python/unitTests.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/test/python/unitTests.py b/ambari-agent/src/test/python/unitTests.py
index 082e1a1..83b6bdf 100644
--- a/ambari-agent/src/test/python/unitTests.py
+++ b/ambari-agent/src/test/python/unitTests.py
@@ -23,7 +23,8 @@ import doctest
 from os.path import dirname, split, isdir
 import logging.handlers
 import logging
-from random import shuffle
+#TODO Add an option to randomize the tests' execution
+#from random import shuffle
 
 LOG_FILE_NAME='tests.log'
 SELECTED_PREFIX = "_"
@@ -55,7 +56,8 @@ def all_tests_suite():
   for directory in os.listdir(src_dir):
     if os.path.isdir(directory):
       files_list += os.listdir(src_dir + os.sep + directory)
-  shuffle(files_list)
+  #TODO Add an option to randomize the tests' execution
+  #shuffle(files_list)
   tests_list = []
 
   logger.info('------------------------TESTS LIST:-------------------------------------')

http://git-wip-us.apache.org/repos/asf/ambari/blob/8de3425f/ambari-client/groovy-client/pom.xml
----------------------------------------------------------------------
diff --git a/ambari-client/groovy-client/pom.xml b/ambari-client/groovy-client/pom.xml
index fbedbd1..cc823de 100644
--- a/ambari-client/groovy-client/pom.xml
+++ b/ambari-client/groovy-client/pom.xml
@@ -87,6 +87,7 @@
         <artifactId>apache-rat-plugin</artifactId>
         <configuration>
           <excludes>
+            <exclude>**/*.iml</exclude>
             <exclude>src/main/resources/blueprints/**</exclude>
             <exclude>src/test/resources/**</exclude>
           </excludes>

http://git-wip-us.apache.org/repos/asf/ambari/blob/8de3425f/ambari-client/python-client/pom.xml
----------------------------------------------------------------------
diff --git a/ambari-client/python-client/pom.xml b/ambari-client/python-client/pom.xml
index 74fc0f5..e16bbc2 100644
--- a/ambari-client/python-client/pom.xml
+++ b/ambari-client/python-client/pom.xml
@@ -75,7 +75,7 @@
         <executions>
           <execution>
             <configuration>
-              <executable>${project.basedir}/../../ambari-common/src/main/unix/ambari-python-wrap</executable>
+              <executable>python</executable>
               <workingDirectory>src/test/python</workingDirectory>
               <arguments>
                 <argument>unitTests.py</argument>
@@ -93,7 +93,7 @@
           </execution>
           <execution>
             <configuration>
-              <executable>${project.basedir}/../../ambari-common/src/main/unix/ambari-python-wrap</executable>
+              <executable>python</executable>
               <workingDirectory>target/python-client-${project.version}</workingDirectory>
               <arguments>
                 <argument>${project.basedir}/src/main/python/setup.py</argument>
@@ -115,7 +115,7 @@
       <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>rpm-maven-plugin</artifactId>
-        <version>2.0.1</version>
+        <version>2.1-alpha-2</version>
         <executions>
           <execution>
             <phase>none</phase>

http://git-wip-us.apache.org/repos/asf/ambari/blob/8de3425f/ambari-common/src/main/python/ambari_commons/ambari_service.py
----------------------------------------------------------------------
diff --git a/ambari-common/src/main/python/ambari_commons/ambari_service.py b/ambari-common/src/main/python/ambari_commons/ambari_service.py
new file mode 100644
index 0000000..8418e74
--- /dev/null
+++ b/ambari-common/src/main/python/ambari_commons/ambari_service.py
@@ -0,0 +1,79 @@
+'''
+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.
+'''
+
+import os
+
+import win32service
+
+from ambari_commons.os_windows import WinService
+
+
+AMBARI_VERSION_VAR = "AMBARI_VERSION_VAR"
+
+ENV_PYTHON_PATH = "PYTHONPATH"
+
+
+class AmbariService(WinService):
+  _svc_name_ = "Ambari Service"
+  _svc_display_name_ = "Ambari Service"
+  _svc_description_ = "Ambari Service"
+
+  # Sets the current dir and adjusts the PYTHONPATH env variable before calling SvcDoRun()
+  def SvcRun(self):
+    self.ReportServiceStatus(win32service.SERVICE_START_PENDING)
+
+    import servicemanager
+
+    parser = self._InitOptionsParser()
+    (self.options, args) = parser.parse_args()
+
+    try:
+      is_debugging = servicemanager.Debugging()
+    except:
+      is_debugging = False
+
+    if not is_debugging:
+      # Save the current dir, or the script dir if none set (typical for services)
+      script_path = os.path.dirname(__file__.replace('/', os.sep))
+      # the script resides in the sbin/ambari_commons subdir
+      self.options.current_dir = os.path.normpath(script_path + "\\..\\..")
+      os.chdir(self.options.current_dir)
+
+      python_path = os.path.normpath(script_path + "\\..")
+
+      #update the environment vars: set PYTHONPATH = $script_dir\sbin;%PYTHONPATH%
+      if os.environ.has_key(ENV_PYTHON_PATH):
+        python_path += os.pathsep + os.environ[ENV_PYTHON_PATH]
+      os.environ[ENV_PYTHON_PATH] = python_path
+
+    self.SvcDoRun()
+    pass
+
+  # Call during initialization to implement standard service versioning
+  @classmethod
+  def _AdjustServiceVersion(cls):
+    if os.environ.has_key(AMBARI_VERSION_VAR):
+      ambariVer = os.environ[AMBARI_VERSION_VAR]
+    else:
+      ambariVer = "1.3.0-SNAPSHOT"
+    AmbariService._svc_display_name_ += "-" + ambariVer
+    AmbariService._svc_description_ += " v" + ambariVer
+
+  # Override to customize the command-line arguments
+  def _InitOptionsParser(self):
+    pass

http://git-wip-us.apache.org/repos/asf/ambari/blob/8de3425f/ambari-common/src/main/python/ambari_commons/exceptions.py
----------------------------------------------------------------------
diff --git a/ambari-common/src/main/python/ambari_commons/exceptions.py b/ambari-common/src/main/python/ambari_commons/exceptions.py
new file mode 100644
index 0000000..c5ed85d
--- /dev/null
+++ b/ambari-common/src/main/python/ambari_commons/exceptions.py
@@ -0,0 +1,35 @@
+#!/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.
+'''
+
+class FatalException(Exception):
+    def __init__(self, code, reason):
+      self.code = code
+      self.reason = reason
+
+    def __str__(self):
+        return repr("Fatal exception: %s, exit code %s" % (self.reason, self.code))
+
+
+class NonFatalException(Exception):
+  def __init__(self, reason):
+    self.reason = reason
+
+  def __str__(self):
+    return repr("NonFatal exception: %s" % self.reason)

http://git-wip-us.apache.org/repos/asf/ambari/blob/8de3425f/ambari-common/src/main/python/ambari_commons/inet_utils.py
----------------------------------------------------------------------
diff --git a/ambari-common/src/main/python/ambari_commons/inet_utils.py b/ambari-common/src/main/python/ambari_commons/inet_utils.py
new file mode 100644
index 0000000..2a54cb6
--- /dev/null
+++ b/ambari-common/src/main/python/ambari_commons/inet_utils.py
@@ -0,0 +1,148 @@
+#!/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.
+'''
+
+import os
+import sys
+import urllib2
+
+from exceptions import *
+from logging_utils import *
+
+def download_file(link, destination, chunk_size=16 * 1024):
+  print_info_msg("Downloading {0} to {1}".format(link, destination))
+  if os.path.exists(destination):
+      print_warning_msg("File {0} already exists, assuming it was downloaded before".format(destination))
+      return
+
+  force_download_file(link, destination, chunk_size)
+
+
+def download_progress(file_name, downloaded_size, blockSize, totalSize):
+  percent = int(downloaded_size * 100 / totalSize)
+  status = "\r" + file_name
+
+  if totalSize < blockSize:
+    status += "... %d%%" % (100)
+  else:
+    status += "... %d%% (%.1f MB of %.1f MB)" % (
+      percent, downloaded_size / 1024 / 1024.0, totalSize / 1024 / 1024.0)
+  sys.stdout.write(status)
+  sys.stdout.flush()
+
+
+def find_range_components(meta):
+  file_size = 0
+  seek_pos = 0
+  hdr_range = meta.getheaders("Content-Range")
+  if len(hdr_range) > 0:
+    range_comp1 = hdr_range[0].split('/')
+    if len(range_comp1) > 1:
+      range_comp2 = range_comp1[0].split(' ') #split away the "bytes" prefix
+      if len(range_comp2) == 0:
+        raise FatalException(12, 'Malformed Content-Range response header: "{}".' % hdr_range)
+      range_comp3 = range_comp2[1].split('-')
+      seek_pos = int(range_comp3[0])
+      if range_comp1[1] != '*': #'*' == unknown length
+        file_size = int(range_comp1[1])
+
+  if file_size == 0:
+    #Try the old-fashioned way
+    hdrLen = meta.getheaders("Content-Length")
+    if len(hdrLen) == 0:
+      raise FatalException(12, "Response header doesn't contain Content-Length. Chunked Transfer-Encoding is not supported for now.")
+    file_size = int(hdrLen[0])
+
+  return (file_size, seek_pos)
+
+
+def force_download_file(link, destination, chunk_size = 16 * 1024, progress_func = download_progress):
+  request = urllib2.Request(link)
+
+  if os.path.exists(destination) and not os.path.isfile(destination):
+    #Directory specified as target? Must be a mistake. Bail out, don't assume anything.
+    err = 'Download target {} is a directory.' % destination
+    raise FatalException(1, err)
+
+  (dest_path, file_name) = os.path.split(destination)
+
+  temp_dest = destination + ".tmpdownload"
+  partial_size = 0
+
+  if os.path.exists(temp_dest):
+    #Support for resuming downloads, in case the process is killed while downloading a file
+    #  set resume range
+    # See http://stackoverflow.com/questions/6963283/python-urllib2-resume-download-doesnt-work-when-network-reconnects
+    partial_size = os.stat(temp_dest).st_size
+    if partial_size > chunk_size:
+      #Re-download the last chunk, to minimize the possibilities of file corruption
+      resume_pos = partial_size - chunk_size
+      request.add_header("Range", "bytes=%s-" % resume_pos)
+  else:
+    #Make sure the full dir structure is in place, otherwise file open will fail
+    if not os.path.exists(dest_path):
+      os.makedirs(dest_path)
+
+  response = urllib2.urlopen(request)
+  (file_size, seek_pos) = find_range_components(response.info())
+
+  print_info_msg("Downloading to: %s Bytes: %s" % (destination, file_size))
+
+  if partial_size < file_size:
+    if seek_pos == 0:
+      #New file, create it
+      open_mode = 'wb'
+    else:
+      #Resuming download of an existing file
+      open_mode = 'rb+' #rb+ doesn't create the file, using wb to create it
+    f = open(temp_dest, open_mode)
+
+    try:
+      #Resume the download from where it left off
+      if seek_pos > 0:
+        f.seek(seek_pos)
+
+      file_size_dl = seek_pos
+      while True:
+        buffer = response.read(chunk_size)
+        if not buffer:
+            break
+
+        file_size_dl += len(buffer)
+        f.write(buffer)
+
+        progress_func(file_name, file_size_dl, chunk_size, file_size)
+    finally:
+      f.close()
+
+    sys.stdout.write('\n')
+    sys.stdout.flush()
+
+  print_info_msg("Finished downloading {0} to {1}".format(link, destination))
+
+  downloaded_size = os.stat(temp_dest).st_size
+  if downloaded_size != file_size:
+    err = 'Size of downloaded file {} is {} bytes, it is probably damaged or incomplete' % (destination, downloaded_size)
+    raise FatalException(1, err)
+
+  # when download is complete -> mv temp_dest destination
+  if os.path.exists(destination):
+    #Windows behavior: rename fails if the destination file exists
+    os.unlink(destination)
+  os.rename(temp_dest, destination)

http://git-wip-us.apache.org/repos/asf/ambari/blob/8de3425f/ambari-common/src/main/python/ambari_commons/logging_utils.py
----------------------------------------------------------------------
diff --git a/ambari-common/src/main/python/ambari_commons/logging_utils.py b/ambari-common/src/main/python/ambari_commons/logging_utils.py
new file mode 100644
index 0000000..9d45fdb
--- /dev/null
+++ b/ambari-common/src/main/python/ambari_commons/logging_utils.py
@@ -0,0 +1,49 @@
+#!/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.
+'''
+
+VERBOSE = False
+SILENT = False
+DEBUG_MODE = False
+
+# terminal styles
+BOLD_ON = '\033[1m'
+BOLD_OFF = '\033[0m'
+
+#
+# Prints an "info" messsage.
+#
+def print_info_msg(msg):
+  if VERBOSE:
+    print("INFO: " + msg)
+
+#
+# Prints an "error" messsage.
+#
+def print_error_msg(msg):
+  print("ERROR: " + msg)
+
+#
+# Prints a "warning" messsage.
+#
+def print_warning_msg(msg, bold=False):
+  if bold:
+    print(BOLD_ON + "WARNING: " + msg + BOLD_OFF)
+  else:
+    print("WARNING: " + msg)

http://git-wip-us.apache.org/repos/asf/ambari/blob/8de3425f/ambari-common/src/main/python/ambari_commons/os_check.py
----------------------------------------------------------------------
diff --git a/ambari-common/src/main/python/ambari_commons/os_check.py b/ambari-common/src/main/python/ambari_commons/os_check.py
index 78cf784..03e94c4 100644
--- a/ambari-common/src/main/python/ambari_commons/os_check.py
+++ b/ambari-common/src/main/python/ambari_commons/os_check.py
@@ -36,16 +36,40 @@ def linux_distribution():
   PYTHON_VER = sys.version_info[0] * 10 + sys.version_info[1]
 
   if PYTHON_VER < 26:
-    linux_distribution = platform.dist()
+    (distname, version, id)  = platform.dist()
   elif os.path.exists('/etc/redhat-release'):
-    linux_distribution = platform.dist()
+    (distname, version, id)  = platform.dist()
   else:
-    linux_distribution = platform.linux_distribution()
+    (distname, version, id) = platform.linux_distribution()
 
-  return linux_distribution
+  return (platform.system(), os.name, distname, version, id)
 
+def windows_distribution():
+  from os_windows import get_windows_version
+
+  # Only support Windows Server 64 bit
+  (win_release, win_version, win_csd, win_ptype) = platform.win32_ver()
+
+  if win_version.startswith("6.2."):
+    # win32_ver() doesn't work correctly for Windows Server 2012 R2 and Windows 8.1
+    (win_ver_major, win_ver_minor, win_ver_build) = get_windows_version()
+    if win_ver_major == 6 and win_ver_minor == 3:
+      win_release = "2012ServerR2"
+      win_version = "%d.%d.%d" % (win_ver_major, win_ver_minor, win_ver_build)
+
+  #if win_version
+  return (platform.system(), os.name, "win" + win_release, win_version, win_ptype)
 
 class OS_CONST_TYPE(type):
+  # os platforms
+  LINUX_OS = 'linux'
+  WINDOWS_OS = 'windows'
+
+  # os families
+  REDHAT_FAMILY = 'redhat'
+  DEBIAN_FAMILY = 'debian'
+  SUSE_FAMILY = 'suse'
+  WINSRV_FAMILY = 'winsrv'
 
   # Declare here os type mapping
   OS_FAMILY_COLLECTION = []
@@ -58,7 +82,8 @@ class OS_CONST_TYPE(type):
       Initialize internal data structures from file
     """
     try:
-      f = open(os.path.join(RESOURCES_DIR, OSFAMILY_JSON_RESOURCE))
+      fpath = os.path.join(RESOURCES_DIR, OSFAMILY_JSON_RESOURCE)
+      f = open(fpath)
       json_data = json.load(f)
       f.close()
       for family in json_data:
@@ -69,7 +94,7 @@ class OS_CONST_TYPE(type):
           'os_list': json_data[family][JSON_OS_TYPE]
         }]
     except:
-      raise Exception("Couldn't load '%s' file" % OSFAMILY_JSON_RESOURCE)
+      raise Exception("Couldn't load '%s' file" % fpath)
 
   def __init__(cls, name, bases, dct):
     cls.initialize_data()
@@ -89,17 +114,45 @@ class OS_CONST_TYPE(type):
       return name[:-7]
     raise Exception("Unknown class property '%s'" % name)
 
+def get_os_distribution():
+  if platform.system() == 'Windows':
+    dist = windows_distribution()
+  else:
+    if platform.system() == 'Mac':
+      raise Exception("MacOS not supported. Exiting...")
+    else:
+      # Linux
+      # Read content from /etc/*-release file
+      # Full release name
+      dist = linux_distribution()
+  return dist
 
 class OSConst:
   __metaclass__ = OS_CONST_TYPE
 
 
 class OSCheck:
+  _dist = get_os_distribution()
+
+  @staticmethod
+  def get_os_os():
+    """
+    Return values:
+    windows, linux
+
+    In case cannot detect - exit.
+    """
+    # Read content from /etc/*-release file
+    # Full release name
+    os_os = OSCheck._dist[0].lower()
+
+    return os_os
 
   @staticmethod
   def get_os_type():
     """
     Return values:
+    win2008server, win2012server,
     redhat, fedora, centos, oraclelinux, ascendos,
     amazon, xenserver, oel, ovs, cloudlinux, slc, scientific, psbm,
     ubuntu, debian, sles, sled, opensuse, suse ... and others
@@ -108,8 +161,7 @@ class OSCheck:
     """
     # Read content from /etc/*-release file
     # Full release name
-    dist = linux_distribution()
-    operatingSystem = dist[0].lower()
+    operatingSystem  = OSCheck._dist[2].lower()
 
     # special cases
     if os.path.exists('/etc/oracle-release'):
@@ -147,10 +199,7 @@ class OSCheck:
 
     In case cannot detect raises exception.
     """
-    # Read content from /etc/*-release file
-    # Full release name
-    dist = linux_distribution()
-    dist = dist[1]
+    dist = OSCheck._dist[3]
 
     if dist:
       return dist
@@ -173,8 +222,7 @@ class OSCheck:
 
     In case cannot detect raises exception.
     """
-    dist = linux_distribution()
-    dist = dist[2].lower()
+    dist = OSCheck._dist[4].lower()
 
     if dist:
       return dist
@@ -226,6 +274,48 @@ class OSCheck:
     return False
 
   @staticmethod
+  def is_windows_family():
+    """
+     Return true if it is so or false if not
+
+     This is safe check for windows family, doesn't generate exception
+    """
+    try:
+      if OSCheck.get_os_family() == OSConst.WINSRV_FAMILY:
+        return True
+    except Exception:
+      pass
+    return False
+
+  @staticmethod
+  def is_linux_os():
+    """
+     Return true if it is so or false if not
+
+     This is safe check for linux os, doesn't generate exception
+    """
+    try:
+      if OSCheck.get_os_os() == OSConst.LINUX_OS:
+        return True
+    except Exception:
+      pass
+    return False
+
+  @staticmethod
+  def is_windows_os():
+    """
+     Return true if it is so or false if not
+
+     This is safe check for windows os, doesn't generate exception
+    """
+    try:
+      if OSCheck.get_os_os() == OSConst.WINDOWS_OS:
+        return True
+    except Exception:
+      pass
+    return False
+
+  @staticmethod
   def is_redhat7():
     """
      Return true if it is so or false if not
@@ -238,4 +328,10 @@ class OSCheck:
         return True
     except Exception:
       pass
-    return False
\ No newline at end of file
+    return False
+
+# OS info
+OS_VERSION = OSCheck().get_os_major_version()
+OS_TYPE = OSCheck.get_os_type()
+OS_FAMILY = OSCheck.get_os_family()
+OS_OS = OSCheck.get_os_os()

http://git-wip-us.apache.org/repos/asf/ambari/blob/8de3425f/ambari-common/src/main/python/ambari_commons/os_linux.py
----------------------------------------------------------------------
diff --git a/ambari-common/src/main/python/ambari_commons/os_linux.py b/ambari-common/src/main/python/ambari_commons/os_linux.py
new file mode 100644
index 0000000..38f3fb9
--- /dev/null
+++ b/ambari-common/src/main/python/ambari_commons/os_linux.py
@@ -0,0 +1,81 @@
+#!/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.
+'''
+import getpass
+
+import os
+import pwd
+import shlex
+import subprocess
+
+from logging_utils import *
+
+
+NR_CHMOD_CMD = 'chmod {0} {1} {2}'
+NR_CHOWN_CMD = 'chown {0} {1} {2}'
+
+ULIMIT_CMD = "ulimit -n"
+
+
+def run_os_command(cmd):
+  print_info_msg('about to run command: ' + str(cmd))
+  if type(cmd) == str:
+    cmd = shlex.split(cmd)
+  process = subprocess.Popen(cmd,
+                             stdout=subprocess.PIPE,
+                             stdin=subprocess.PIPE,
+                             stderr=subprocess.PIPE
+                             )
+  (stdoutdata, stderrdata) = process.communicate()
+  return process.returncode, stdoutdata, stderrdata
+
+def os_change_owner(filePath, user):
+  uid = pwd.getpwnam(user).pw_uid
+  gid = pwd.getpwnam(user).pw_gid
+  os.chown(filePath, uid, gid)
+
+def os_is_root():
+  '''
+  Checks effective UUID
+  Returns True if a program is running under root-level privileges.
+  '''
+  return os.geteuid() == 0
+
+def os_set_file_permissions(file, mod, recursive, user):
+  WARN_MSG = "Command {0} returned exit code {1} with message: {2}"
+  if recursive:
+    params = " -R "
+  else:
+    params = ""
+  command = NR_CHMOD_CMD.format(params, mod, file)
+  retcode, out, err = run_os_command(command)
+  if retcode != 0:
+    print_warning_msg(WARN_MSG.format(command, file, err))
+  command = NR_CHOWN_CMD.format(params, user, file)
+  retcode, out, err = run_os_command(command)
+  if retcode != 0:
+    print_warning_msg(WARN_MSG.format(command, file, err))
+
+def os_set_open_files_limit(maxOpenFiles):
+  command = "%s %s" % (ULIMIT_CMD, str(maxOpenFiles))
+  run_os_command(command)
+
+
+def os_getpass(prompt):
+  return getpass.unix_getpass(prompt)

http://git-wip-us.apache.org/repos/asf/ambari/blob/8de3425f/ambari-common/src/main/python/ambari_commons/os_utils.py
----------------------------------------------------------------------
diff --git a/ambari-common/src/main/python/ambari_commons/os_utils.py b/ambari-common/src/main/python/ambari_commons/os_utils.py
new file mode 100644
index 0000000..9ea423f
--- /dev/null
+++ b/ambari-common/src/main/python/ambari_commons/os_utils.py
@@ -0,0 +1,102 @@
+#!/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.
+'''
+
+import shutil
+import string
+
+from os_check import *
+
+if OSCheck.is_windows_os():
+  from os_windows import *
+else:
+  # MacOS not supported
+  from os_linux import *
+
+from logging_utils import *
+from exceptions import FatalException
+
+
+def is_valid_filepath(filepath):
+  if not filepath or not os.path.exists(filepath) or os.path.isdir(filepath):
+    print 'Invalid path, please provide the absolute file path.'
+    return False
+  else:
+    return True
+
+def quote_path(filepath):
+  if(filepath.find(' ') != -1):
+    filepath_ret = '"' + filepath + '"'
+  else:
+    filepath_ret = filepath
+  return filepath_ret
+
+def search_file(filename, search_path, pathsep=os.pathsep):
+  """ Given a search path, find file with requested name """
+  for path in string.split(search_path, pathsep):
+    candidate = os.path.join(path, filename)
+    if os.path.exists(candidate):
+      return os.path.abspath(candidate)
+  return None
+
+def copy_file(src, dest_file):
+  try:
+    shutil.copyfile(src, dest_file)
+  except Exception, e:
+    err = "Can not copy file {0} to {1} due to: {2} . Please check file " \
+              "permissions and free disk space.".format(src, dest_file, e.message)
+    raise FatalException(1, err)
+
+def copy_files(files, dest_dir):
+  if os.path.isdir(dest_dir):
+    for filepath in files:
+      shutil.copy(filepath, dest_dir)
+    return 0
+  else:
+    return -1
+
+def remove_file(filePath):
+  if os.path.exists(filePath):
+    try:
+      os.remove(filePath)
+    except Exception, e:
+      print_warning_msg('Unable to remove file: ' + str(e))
+      return 1
+  pass
+  return 0
+
+def set_file_permissions(file, mod, user, recursive):
+  if os.path.exists(file):
+    os_set_file_permissions(file, mod, recursive, user)
+  else:
+    print_info_msg("File %s does not exist" % file)
+
+def is_root():
+  return os_is_root()
+
+# Proxy to the os implementation
+def change_owner(filePath, user):
+  os_change_owner(filePath, user)
+
+# Proxy to the os implementation
+def set_open_files_limit(maxOpenFiles):
+  os_set_open_files_limit(maxOpenFiles)
+
+def get_password(prompt):
+  return os_getpass(prompt)
\ No newline at end of file