AMBARI-18934 - Management packs should be able to link grafana dashboards and 
service metrics for custom services


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/4a7cbcb1
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/4a7cbcb1
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/4a7cbcb1

Branch: refs/heads/branch-feature-AMBARI-18634
Commit: 4a7cbcb1b49d070f57c9d5ba9771ad72765693a4
Parents: 2ce9e3b
Author: Tim Thorpe <ttho...@apache.org>
Authored: Tue Nov 22 07:52:49 2016 -0800
Committer: Tim Thorpe <ttho...@apache.org>
Committed: Tue Nov 22 07:52:49 2016 -0800

----------------------------------------------------------------------
 ambari-server/pom.xml                           |   2 +
 .../python/ambari_server/serverConfiguration.py |   9 +-
 .../main/python/ambari_server/setupMpacks.py    | 105 ++++++--
 ambari-server/src/test/python/TestMpacks.py     | 217 +++++++++++----
 .../grafana-dashboards/grafana-hdfs-users.json  | 270 +++++++++++++++++++
 .../dashboards/service-metrics/STORM.txt        |   7 +
 .../python/uninstall/common-services/SERVICEA   |   1 +
 .../python/uninstall/common-services/SERVICEB   |   1 +
 .../test/python/uninstall/dashboards/SERVICEA   |   1 +
 .../test/python/uninstall/dashboards/SERVICEB   |   1 +
 .../uninstall/dashboards/files/README.txt       |  17 ++
 .../python/uninstall/dashboards/files/STORM.txt |   1 +
 .../uninstall/dashboards/files/metainfo.xml     |   1 +
 .../test/python/uninstall/extensions/SERVICEA   |   1 +
 .../test/python/uninstall/extensions/SERVICEB   |   1 +
 .../test/python/uninstall/stacks/2.0/SERVICEA   |   1 +
 .../test/python/uninstall/stacks/2.0/SERVICEB   |   1 +
 .../uninstall/stacks/2.0/files/README.txt       |  17 ++
 .../uninstall/stacks/2.0/files/metainfo1.xml    |   1 +
 .../uninstall/stacks/2.0/files/metainfo2.xml    |   1 +
 20 files changed, 586 insertions(+), 70 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/4a7cbcb1/ambari-server/pom.xml
----------------------------------------------------------------------
diff --git a/ambari-server/pom.xml b/ambari-server/pom.xml
index 36c57de..69ab9d0 100644
--- a/ambari-server/pom.xml
+++ b/ambari-server/pom.xml
@@ -274,6 +274,8 @@
             <exclude>src/test/resources/users.ldif</exclude>
             <exclude>src/test/resources/mpacks_replay.log</exclude>
             <exclude>src/test/python/stacks/2.5/HIVE/*.txt</exclude>
+            
<exclude>src/test/python/mpacks/mystack-ambari-mpack-1.0.0.1/stacks/MYSTACK/3.0/services/SERVICEC/dashboards/service-metrics/STORM.txt</exclude>
+            
<exclude>src/test/python/uninstall/dashboards/files/STORM.txt</exclude>
             <exclude>src/main/resources/hive-schema-0.10.0.oracle.sql</exclude>
             <exclude>src/main/resources/hive-schema-0.12.0.oracle.sql</exclude>
             <exclude>src/main/resources/db/serial</exclude>

http://git-wip-us.apache.org/repos/asf/ambari/blob/4a7cbcb1/ambari-server/src/main/python/ambari_server/serverConfiguration.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/python/ambari_server/serverConfiguration.py 
b/ambari-server/src/main/python/ambari_server/serverConfiguration.py
index 3086003..9596e0d 100644
--- a/ambari-server/src/main/python/ambari_server/serverConfiguration.py
+++ b/ambari-server/src/main/python/ambari_server/serverConfiguration.py
@@ -186,6 +186,7 @@ SETUP_OR_UPGRADE_MSG = "- If this is a new setup, then run 
the \"ambari-server s
 DEFAULT_DB_NAME = "ambari"
 
 SECURITY_KEYS_DIR = "security.server.keys_dir"
+DASHBOARD_PATH_PROPERTY = 'dashboards.path'
 EXTENSION_PATH_PROPERTY = 'extensions.path'
 COMMON_SERVICES_PATH_PROPERTY = 'common.services.path'
 MPACKS_STAGING_PATH_PROPERTY = 'mpacks.staging.path'
@@ -1447,7 +1448,13 @@ def get_mpacks_staging_location(properties):
 # Dashboard location
 #
 def get_dashboard_location(properties):
-  dashboard_location = configDefaults.DASHBOARD_LOCATION_DEFAULT
+  try:
+    dashboard_location = properties[DASHBOARD_PATH_PROPERTY]
+  except KeyError:
+    dashboard_location = configDefaults.DASHBOARD_LOCATION_DEFAULT
+
+  if not dashboard_location:
+    dashboard_location = configDefaults.DASHBOARD_LOCATION_DEFAULT
   return dashboard_location
 
 #

http://git-wip-us.apache.org/repos/asf/ambari/blob/4a7cbcb1/ambari-server/src/main/python/ambari_server/setupMpacks.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/python/ambari_server/setupMpacks.py 
b/ambari-server/src/main/python/ambari_server/setupMpacks.py
index 773d946..131e14d 100755
--- a/ambari-server/src/main/python/ambari_server/setupMpacks.py
+++ b/ambari-server/src/main/python/ambari_server/setupMpacks.py
@@ -32,7 +32,7 @@ from ambari_commons.logging_utils import print_info_msg, 
print_error_msg, print_
 from ambari_commons.os_utils import copy_file, run_os_command
 from ambari_server.serverConfiguration import get_ambari_properties, 
get_ambari_version, get_stack_location, \
   get_common_services_location, get_mpacks_staging_location, 
get_server_temp_location, get_extension_location, \
-  get_java_exe_path, read_ambari_user, parse_properties_file, 
JDBC_DATABASE_PROPERTY
+  get_java_exe_path, read_ambari_user, parse_properties_file, 
JDBC_DATABASE_PROPERTY, get_dashboard_location
 from ambari_server.setupSecurity import ensure_can_start_under_current_user, 
generate_env
 from ambari_server.setupActions import INSTALL_MPACK_ACTION, 
UPGRADE_MPACK_ACTION
 from ambari_server.userInput import get_YN_input
@@ -50,6 +50,12 @@ logger = logging.getLogger(__name__)
 
 MPACKS_REPLAY_LOG_FILENAME = "mpacks_replay.log"
 MPACKS_CACHE_DIRNAME = "cache"
+SERVICES_DIRNAME = "services"
+DASHBOARDS_DIRNAME = "dashboards"
+GRAFANA_DASHBOARDS_DIRNAME = "grafana-dashboards"
+SERVICE_METRICS_DIRNAME = "service-metrics"
+METRICS_EXTENSION = ".txt"
+
 STACK_DEFINITIONS_RESOURCE_NAME = "stack-definitions"
 EXTENSION_DEFINITIONS_RESOURCE_NAME = "extension-definitions"
 SERVICE_DEFINITIONS_RESOURCE_NAME = "service-definitions"
@@ -187,8 +193,9 @@ def get_mpack_properties():
   extension_location = get_extension_location(properties)
   service_definitions_location = get_common_services_location(properties)
   mpacks_staging_location = get_mpacks_staging_location(properties)
+  dashboard_location = get_dashboard_location(properties)
   ambari_version = get_ambari_version(properties)
-  return stack_location, extension_location, service_definitions_location, 
mpacks_staging_location
+  return stack_location, extension_location, service_definitions_location, 
mpacks_staging_location, dashboard_location
 
 def _get_mpack_name_version(mpack_path):
   """
@@ -225,22 +232,35 @@ def create_symlink(src_dir, dest_dir, file_name, 
force=False):
   """
   src_path = os.path.join(src_dir, file_name)
   dest_link = os.path.join(dest_dir, file_name)
+  create_symlink_using_path(src_path, dest_link, force)
+
+def create_symlink_using_path(src_path, dest_link, force=False):
+  """
+  Helper function to create symbolic link (dest_link -> src_path)
+  :param src_path: Source path
+  :param dest_link: Destination link
+  :param force: Remove existing symlink
+  """
   if force and os.path.islink(dest_link):
     sudo.unlink(dest_link)
   sudo.symlink(src_path, dest_link)
   print_info_msg("Symlink: " + dest_link)
 
-def remove_symlinks(stack_location, service_definitions_location, 
staged_mpack_dir):
+def remove_symlinks(stack_location, extension_location, 
service_definitions_location, dashboard_location, staged_mpack_dir):
   """
   Helper function to remove all symbolic links pointed to a management pack
   :param stack_location: Path to stacks folder
                          (/var/lib/ambari-server/resources/stacks)
+  :param extension_location: Path to extensions folder
+                             (/var/lib/ambari-server/resources/extension)
   :param service_definitions_location: Path to service_definitions folder
                                       
(/var/lib/ambari-server/resources/common-services)
+  :param dashboard_location: Path to the custom service dashboard folder
+                             (/var/lib/ambari-server/resources/dashboards)
   :param staged_mpack_dir: Path to management pack staging location
                            
(/var/lib/ambari-server/resources/mpacks/mpack_name-mpack_version)
   """
-  for location in [stack_location, service_definitions_location]:
+  for location in [stack_location, extension_location, 
service_definitions_location, dashboard_location]:
     for root, dirs, files in os.walk(location):
       for name in files:
         file = os.path.join(root, name)
@@ -292,7 +312,7 @@ def validate_purge(options, purge_list, mpack_dir, 
mpack_metadata, replay_mode=F
   :param replay_mode: Flag to indicate if purging in replay mode
   """
   # Get ambari mpacks config properties
-  stack_location, extension_location, service_definitions_location, 
mpacks_staging_location = get_mpack_properties()
+  stack_location, extension_location, service_definitions_location, 
mpacks_staging_location, dashboard_location = get_mpack_properties()
 
   if not purge_list:
     return
@@ -338,7 +358,7 @@ def purge_stacks_and_mpacks(purge_list, replay_mode=False):
   :param replay_mode: Flag to indicate if purging in replay mode
   """
   # Get ambari mpacks config properties
-  stack_location, extension_location, service_definitions_location, 
mpacks_staging_location = get_mpack_properties()
+  stack_location, extension_location, service_definitions_location, 
mpacks_staging_location, dashboard_location = get_mpack_properties()
 
   print_info_msg("Purging existing stack definitions and management packs")
 
@@ -376,7 +396,7 @@ def process_stack_definitions_artifact(artifact, 
artifact_source_dir, options):
   :param options: Command line options
   """
   # Get ambari mpack properties
-  stack_location, extension_location, service_definitions_location, 
mpacks_staging_location = get_mpack_properties()
+  stack_location, extension_location, service_definitions_location, 
mpacks_staging_location, dashboard_location = get_mpack_properties()
   for file in sorted(os.listdir(artifact_source_dir)):
     if os.path.isfile(os.path.join(artifact_source_dir, file)):
       # Example: /var/lib/ambari-server/resources/stacks/stack_advisor.py
@@ -395,16 +415,53 @@ def process_stack_definitions_artifact(artifact, 
artifact_source_dir, options):
           if not os.path.exists(dest_stack_version_dir):
             sudo.makedir(dest_stack_version_dir, 0755)
           for file in sorted(os.listdir(src_stack_version_dir)):
-            if file == "services":
+            if file == SERVICES_DIRNAME:
               src_stack_services_dir = os.path.join(src_stack_version_dir, 
file)
               dest_stack_services_dir = os.path.join(dest_stack_version_dir, 
file)
               if not os.path.exists(dest_stack_services_dir):
                 sudo.makedir(dest_stack_services_dir, 0755)
               for file in sorted(os.listdir(src_stack_services_dir)):
                 create_symlink(src_stack_services_dir, 
dest_stack_services_dir, file, options.force)
+                src_service_dir = os.path.join(src_stack_services_dir, file)
+                create_dashboard_symlinks(src_service_dir, file, 
dashboard_location, options)
             else:
               create_symlink(src_stack_version_dir, dest_stack_version_dir, 
file, options.force)
 
+def create_dashboard_symlinks(src_service_dir, service_name, 
dashboard_location, options):
+  """
+  If there is a dashboards directory under the src_service_dir, 
+  create symlinks under the dashboard_location for the grafana_dashboards
+  and the service-metrics
+  :param src_service_dir: Location of the service directory in the management 
pack
+  :param service_name: Name of the service directory
+  :param dashboard_location: Location of the dashboards directory in 
ambari-server/resources
+  :param options: Command line options
+  """
+  src_dashboards_dir = os.path.join(src_service_dir, DASHBOARDS_DIRNAME)
+  if not os.path.exists(src_dashboards_dir):
+    return
+
+  src_grafana_dashboards_dir = os.path.join(src_dashboards_dir, 
GRAFANA_DASHBOARDS_DIRNAME)
+  src_metrics_dir = os.path.join(src_dashboards_dir, SERVICE_METRICS_DIRNAME)
+  if os.path.exists(src_grafana_dashboards_dir):
+    dest_grafana_dashboards_dir = os.path.join(dashboard_location, 
GRAFANA_DASHBOARDS_DIRNAME)
+    dest_service_dashboards_link = os.path.join(dest_grafana_dashboards_dir, 
service_name)
+    if os.path.exists(dest_service_dashboards_link):
+      message = "Grafana dashboards already exist for service 
{0}.".format(service_name)
+      print_warning_msg(message)
+    else:
+      create_symlink_using_path(src_grafana_dashboards_dir, 
dest_service_dashboards_link, options.force)
+
+  service_metrics_filename = service_name + METRICS_EXTENSION
+  src_metrics_file = os.path.join(src_metrics_dir, service_metrics_filename)
+  if os.path.exists(src_metrics_file):
+    dest_metrics_dir = os.path.join(dashboard_location, 
SERVICE_METRICS_DIRNAME)
+    if os.path.exists(os.path.join(dest_metrics_dir, 
service_metrics_filename)):
+      message = "Service metrics already exist for service 
{0}.".format(service_name)
+      print_warning_msg(message)
+    else:
+      create_symlink(src_metrics_dir, dest_metrics_dir, 
service_metrics_filename, options.force)
+
 def process_extension_definitions_artifact(artifact, artifact_source_dir, 
options):
   """
   Process extension-definitions artifacts
@@ -417,7 +474,7 @@ def process_extension_definitions_artifact(artifact, 
artifact_source_dir, option
   :param options: Command line options
   """
   # Get ambari mpack properties
-  stack_location, extension_location, service_definitions_location, 
mpacks_staging_location = get_mpack_properties()
+  stack_location, extension_location, service_definitions_location, 
mpacks_staging_location, dashboard_location = get_mpack_properties()
   if not os.path.exists(extension_location):
     sudo.makedir(extension_location, 0755)
   for file in sorted(os.listdir(artifact_source_dir)):
@@ -431,6 +488,12 @@ def process_extension_definitions_artifact(artifact, 
artifact_source_dir, option
         sudo.makedir(dest_extension_dir, 0755)
       for file in sorted(os.listdir(src_extension_dir)):
         create_symlink(src_extension_dir, dest_extension_dir, file, 
options.force)
+        src_extension_version_dir = os.path.join(src_extension_dir, file)
+        src_services_dir = os.path.join(src_extension_version_dir, 
SERVICES_DIRNAME)
+        if os.path.exists(src_services_dir):
+          for file in sorted(os.listdir(src_services_dir)):
+            src_service_dir = os.path.join(src_services_dir, file)
+            create_dashboard_symlinks(src_service_dir, file, 
dashboard_location, options) 
 
 def process_service_definitions_artifact(artifact, artifact_source_dir, 
options):
   """
@@ -440,14 +503,17 @@ def process_service_definitions_artifact(artifact, 
artifact_source_dir, options)
   :param options: Command line options
   """
   # Get ambari mpack properties
-  stack_location, extension_location, service_definitions_location, 
mpacks_staging_location = get_mpack_properties()
+  stack_location, extension_location, service_definitions_location, 
mpacks_staging_location, dashboard_location = get_mpack_properties()
   for file in sorted(os.listdir(artifact_source_dir)):
+    service_name = file
     src_service_definitions_dir = os.path.join(artifact_source_dir, file)
     dest_service_definitions_dir = os.path.join(service_definitions_location, 
file)
     if not os.path.exists(dest_service_definitions_dir):
       sudo.makedir(dest_service_definitions_dir, 0755)
     for file in sorted(os.listdir(src_service_definitions_dir)):
       create_symlink(src_service_definitions_dir, 
dest_service_definitions_dir, file, options.force)
+      src_service_version_dir = os.path.join(src_service_definitions_dir, file)
+      create_dashboard_symlinks(src_service_version_dir, service_name, 
dashboard_location, options)
 
 def process_stack_addon_service_definitions_artifact(artifact, 
artifact_source_dir, options):
   """
@@ -457,7 +523,7 @@ def 
process_stack_addon_service_definitions_artifact(artifact, artifact_source_d
   :param options: Command line options
   """
   # Get ambari mpack properties
-  stack_location, extension_location, service_definitions_location, 
mpacks_staging_location = get_mpack_properties()
+  stack_location, extension_location, service_definitions_location, 
mpacks_staging_location, dashboard_location = get_mpack_properties()
   service_versions_map = None
   if "service_versions_map" in artifact:
     service_versions_map = artifact.service_versions_map
@@ -477,7 +543,7 @@ def 
process_stack_addon_service_definitions_artifact(artifact, artifact_source_d
             stack_version = applicable_stack.stack_version
             dest_stack_path = os.path.join(stack_location, stack_name)
             dest_stack_version_path = os.path.join(dest_stack_path, 
stack_version)
-            dest_stack_services_path = os.path.join(dest_stack_version_path, 
"services")
+            dest_stack_services_path = os.path.join(dest_stack_version_path, 
SERVICES_DIRNAME)
             dest_link = os.path.join(dest_stack_services_path, service_name)
             if os.path.exists(dest_stack_path) and 
os.path.exists(dest_stack_version_path):
               if not os.path.exists(dest_stack_services_path):
@@ -485,6 +551,7 @@ def 
process_stack_addon_service_definitions_artifact(artifact, artifact_source_d
               if options.force and os.path.islink(dest_link):
                 sudo.unlink(dest_link)
               sudo.symlink(source_service_version_path, dest_link)
+              create_dashboard_symlinks(source_service_version_path, 
service_name, dashboard_location, options)
 
 def search_mpacks(mpack_name, max_mpack_version=None):
   """
@@ -495,7 +562,7 @@ def search_mpacks(mpack_name, max_mpack_version=None):
   :return: List of management pack
   """
   # Get ambari mpack properties
-  stack_location, extension_location, service_definitions_location, 
mpacks_staging_location = get_mpack_properties()
+  stack_location, extension_location, service_definitions_location, 
mpacks_staging_location, dashboard_location = get_mpack_properties()
   results = []
   if os.path.exists(mpacks_staging_location) and 
os.path.isdir(mpacks_staging_location):
     staged_mpack_dirs = sorted(os.listdir(mpacks_staging_location))
@@ -534,7 +601,7 @@ def uninstall_mpack(mpack_name, mpack_version):
   """
   print_info_msg("Uninstalling management pack {0}-{1}".format(mpack_name, 
mpack_version))
   # Get ambari mpack properties
-  stack_location, extension_location, service_definitions_location, 
mpacks_staging_location = get_mpack_properties()
+  stack_location, extension_location, service_definitions_location, 
mpacks_staging_location, dashboard_location = get_mpack_properties()
   found = False
   if os.path.exists(mpacks_staging_location) and 
os.path.isdir(mpacks_staging_location):
     staged_mpack_dirs = sorted(os.listdir(mpacks_staging_location))
@@ -553,7 +620,7 @@ def uninstall_mpack(mpack_name, mpack_version):
         if mpack_name == staged_mpack_name and 
compare_versions(staged_mpack_version, mpack_version, format=True) == 0:
           print_info_msg("Removing management pack staging location 
{0}".format(staged_mpack_dir))
           sudo.rmtree(staged_mpack_dir)
-          remove_symlinks(stack_location, service_definitions_location, 
staged_mpack_dir)
+          remove_symlinks(stack_location, extension_location, 
service_definitions_location, dashboard_location, staged_mpack_dir)
           found = True
           break
   if not found:
@@ -652,7 +719,7 @@ def _install_mpack(options, replay_mode=False, 
is_upgrade=False):
     purge_stacks_and_mpacks(purge_resources, replay_mode)
 
   # Get ambari mpack properties
-  stack_location, extension_location, service_definitions_location, 
mpacks_staging_location = get_mpack_properties()
+  stack_location, extension_location, service_definitions_location, 
mpacks_staging_location, dashboard_location = get_mpack_properties()
   mpacks_cache_location = os.path.join(mpacks_staging_location, 
MPACKS_CACHE_DIRNAME)
   # Create directories
   if not os.path.exists(stack_location):
@@ -665,6 +732,10 @@ def _install_mpack(options, replay_mode=False, 
is_upgrade=False):
     sudo.makedir(mpacks_staging_location, 0755)
   if not os.path.exists(mpacks_cache_location):
     sudo.makedir(mpacks_cache_location, 0755)
+  if not os.path.exists(dashboard_location):
+    sudo.makedir(dashboard_location, 0755)
+    sudo.makedir(os.path.join(dashboard_location, GRAFANA_DASHBOARDS_DIRNAME), 
0755)
+    sudo.makedir(os.path.join(dashboard_location, SERVICE_METRICS_DIRNAME), 
0755)
 
   # Stage management pack (Stage at 
/var/lib/ambari-server/resources/mpacks/mpack_name-mpack_version)
   mpack_name = mpack_metadata.name
@@ -743,7 +814,7 @@ def get_replay_log_file():
   Helper function to get mpack replay log file path
   :return: mpack replay log file path
   """
-  stack_location, extension_location, service_definitions_location, 
mpacks_staging_location = get_mpack_properties()
+  stack_location, extension_location, service_definitions_location, 
mpacks_staging_location, dashboard_location = get_mpack_properties()
   replay_log_file = os.path.join(mpacks_staging_location, 
MPACKS_REPLAY_LOG_FILENAME)
   return replay_log_file
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/4a7cbcb1/ambari-server/src/test/python/TestMpacks.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/python/TestMpacks.py 
b/ambari-server/src/test/python/TestMpacks.py
index 7fb21ae..8329cf0 100644
--- a/ambari-server/src/test/python/TestMpacks.py
+++ b/ambari-server/src/test/python/TestMpacks.py
@@ -48,9 +48,10 @@ with patch.object(platform, "linux_distribution", 
return_value = MagicMock(retur
                 serverConfiguration.search_file = _search_file
 
 from ambari_server.setupMpacks import install_mpack, upgrade_mpack, 
replay_mpack_logs, \
-  purge_stacks_and_mpacks, validate_purge, read_mpack_metadata, \
+  purge_stacks_and_mpacks, validate_purge, read_mpack_metadata, 
uninstall_mpack, \
   STACK_DEFINITIONS_RESOURCE_NAME, EXTENSION_DEFINITIONS_RESOURCE_NAME, \
-  SERVICE_DEFINITIONS_RESOURCE_NAME, MPACKS_RESOURCE_NAME
+  SERVICE_DEFINITIONS_RESOURCE_NAME, MPACKS_RESOURCE_NAME, 
GRAFANA_DASHBOARDS_DIRNAME, \
+  DASHBOARDS_DIRNAME, SERVICE_METRICS_DIRNAME
 
 with patch.object(os, "geteuid", new=MagicMock(return_value=0)):
   from resource_management.core import sudo
@@ -63,6 +64,7 @@ def get_configs():
     serverConfiguration.STACK_LOCATION_KEY : 
"/var/lib/ambari-server/resources/stacks",
     serverConfiguration.COMMON_SERVICES_PATH_PROPERTY : 
"/var/lib/ambari-server/resources/common-services",
     serverConfiguration.EXTENSION_PATH_PROPERTY : 
"/var/lib/ambari-server/resources/extensions",
+    serverConfiguration.DASHBOARD_PATH_PROPERTY : 
"/var/lib/ambari-server/resources/dashboards",
     serverConfiguration.MPACKS_STAGING_PATH_PROPERTY : mpacks_directory,
     serverConfiguration.SERVER_TMP_DIR_PROPERTY : "/tmp",
     serverConfiguration.JDBC_DATABASE_PROPERTY: "postgres"
@@ -71,6 +73,7 @@ def get_configs():
 
 configs = get_configs()
 
+
 class TestMpacks(TestCase):
 
   def test_install_mpack_with_no_mpack_path(self):
@@ -272,20 +275,30 @@ class TestMpacks(TestCase):
                             
call('/var/lib/ambari-server/resources/common-services'),
                             call(mpacks_directory),
                             call(mpacks_directory + '/cache'),
+                            
call('/var/lib/ambari-server/resources/dashboards'),
                             call(mpacks_directory + 
'/mystack-ambari-mpack-1.0.0.0'),
                             
call('/var/lib/ambari-server/resources/common-services/SERVICEA'),
+                            call(mpacks_directory + 
'/mystack-ambari-mpack-1.0.0.0/common-services/SERVICEA/1.0/dashboards'),
+                            call(mpacks_directory + 
'/mystack-ambari-mpack-1.0.0.0/common-services/SERVICEA/2.0/dashboards'),
                             
call('/var/lib/ambari-server/resources/common-services/SERVICEB'),
+                            call(mpacks_directory + 
'/mystack-ambari-mpack-1.0.0.0/common-services/SERVICEB/1.0.0/dashboards'),
+                            call(mpacks_directory + 
'/mystack-ambari-mpack-1.0.0.0/common-services/SERVICEB/2.0.0/dashboards'),
                             
call('/var/lib/ambari-server/resources/stacks/MYSTACK'),
                             
call('/var/lib/ambari-server/resources/stacks/MYSTACK/1.0'),
                             
call('/var/lib/ambari-server/resources/stacks/MYSTACK/1.0/services'),
+                            call(mpacks_directory + 
'/mystack-ambari-mpack-1.0.0.0/stacks/MYSTACK/1.0/services/SERVICEA/dashboards'),
                             
call('/var/lib/ambari-server/resources/stacks/MYSTACK/1.1'),
                             
call('/var/lib/ambari-server/resources/stacks/MYSTACK/1.1/services'),
+                            call(mpacks_directory + 
'/mystack-ambari-mpack-1.0.0.0/stacks/MYSTACK/1.1/services/SERVICEA/dashboards'),
                             
call('/var/lib/ambari-server/resources/stacks/MYSTACK/2.0'),
                             
call('/var/lib/ambari-server/resources/stacks/MYSTACK/2.0/services'),
+                            call(mpacks_directory + 
'/mystack-ambari-mpack-1.0.0.0/stacks/MYSTACK/2.0/services/SERVICEA/dashboards'),
+                            call(mpacks_directory + 
'/mystack-ambari-mpack-1.0.0.0/stacks/MYSTACK/2.0/services/SERVICEB/dashboards'),
                             call(mpacks_directory + 
'/mystack-ambari-mpack-1.0.0.0/hooks/after_install.py')]
     """
-    os_path_exists_mock.side_effect = [True, True, True, False, True, False, 
False, False,
+    os_path_exists_mock.side_effect = [True, True, True, False, True, False, 
False, False, False,
                                        False, False, False, False, False, 
False,
+                                       False, False, False, False, False, 
False, False, False,
                                        False, False, False, False, True]
     get_ambari_properties_mock.return_value = configs
     shutil_move_mock.return_value = True
@@ -296,6 +309,7 @@ class TestMpacks(TestCase):
     common_services_directory = 
configs[serverConfiguration.COMMON_SERVICES_PATH_PROPERTY]
     extensions_directory = configs[serverConfiguration.EXTENSION_PATH_PROPERTY]
     mpacks_directory = 
configs[serverConfiguration.MPACKS_STAGING_PATH_PROPERTY]
+    dashboards_directory = serverConfiguration.get_dashboard_location(configs)
     mpacks_staging_directory = os.path.join(mpacks_directory, 
"mystack-ambari-mpack-1.0.0.0")
 
     run_os_command_calls = [
@@ -314,6 +328,9 @@ class TestMpacks(TestCase):
       call(common_services_directory),
       call(mpacks_directory),
       call(mpacks_directory + '/cache'),
+      call(dashboards_directory),
+      call(os.path.join(dashboards_directory, GRAFANA_DASHBOARDS_DIRNAME)),
+      call(os.path.join(dashboards_directory, SERVICE_METRICS_DIRNAME)),
       call(os.path.join(common_services_directory, "SERVICEA")),
       call(os.path.join(common_services_directory, "SERVICEB")),
       call(os.path.join(stacks_directory, "MYSTACK")),
@@ -385,7 +402,19 @@ class TestMpacks(TestCase):
     download_mpack_mock.return_value = "/tmp/myextension.tar.gz"
     expand_mpack_mock.return_value = "mpacks/myextension-ambari-mpack-1.0.0.0"
     get_ambari_version_mock.return_value = "2.4.0.0"
-    """
+    
+    os_path_exists_mock.side_effect = [True, True, True, False, True, False, 
False, False,
+                                       False, True, False, False, False]
+    get_ambari_properties_mock.return_value = configs
+    shutil_move_mock.return_value = True
+
+    install_mpack(options)
+
+    extensions_directory = configs[serverConfiguration.EXTENSION_PATH_PROPERTY]
+    mpacks_directory = 
configs[serverConfiguration.MPACKS_STAGING_PATH_PROPERTY]
+    mpacks_staging_directory = os.path.join(mpacks_directory, 
"myextension-ambari-mpack-1.0.0.0")
+    dashboards_directory = serverConfiguration.get_dashboard_location(configs)
+
     os_path_exists_calls = [call('/tmp/myextension.tar.gz'),
                             
call('mpacks/myextension-ambari-mpack-1.0.0.0/mpack.json'),
                             call('/var/lib/ambari-server/resources/stacks'),
@@ -393,24 +422,20 @@ class TestMpacks(TestCase):
                             
call('/var/lib/ambari-server/resources/common-services'),
                             call(mpacks_directory),
                             call(mpacks_directory + '/cache'),
+                            
call('/var/lib/ambari-server/resources/dashboards'),
                             call(mpacks_directory + 
'/myextension-ambari-mpack-1.0.0.0'),
                             
call('/var/lib/ambari-server/resources/extensions'),
-                            
call('/var/lib/ambari-server/resources/extensions/MYEXTENSION')]
-    """
-    os_path_exists_mock.side_effect = [True, True, True, False, True, False, 
False,
-                                       False, True, False]
-    get_ambari_properties_mock.return_value = configs
-    shutil_move_mock.return_value = True
+                            
call('/var/lib/ambari-server/resources/extensions/MYEXTENSION'),
+                            call(mpacks_directory + 
'/myextension-ambari-mpack-1.0.0.0/extensions/MYEXTENSION/1.0/services'),
+                            call(mpacks_directory + 
'/myextension-ambari-mpack-1.0.0.0/extensions/MYEXTENSION/1.1/services')]
 
-    install_mpack(options)
-
-    extensions_directory = configs[serverConfiguration.EXTENSION_PATH_PROPERTY]
-    mpacks_directory = 
configs[serverConfiguration.MPACKS_STAGING_PATH_PROPERTY]
-    mpacks_staging_directory = os.path.join(mpacks_directory, 
"myextension-ambari-mpack-1.0.0.0")
     os_mkdir_calls = [
       call(extensions_directory),
       call(mpacks_directory),
       call(mpacks_directory + '/cache'),
+      call(dashboards_directory),
+      call(os.path.join(dashboards_directory, GRAFANA_DASHBOARDS_DIRNAME)),
+      call(os.path.join(dashboards_directory, SERVICE_METRICS_DIRNAME)),
       call(os.path.join(extensions_directory, "MYEXTENSION"))
     ]
     create_symlink_calls = [
@@ -422,6 +447,7 @@ class TestMpacks(TestCase):
            "1.1", None)
     ]
 
+    os_path_exists_mock.assert_has_calls(os_path_exists_calls)
     self.assertFalse(purge_stacks_and_mpacks_mock.called)
     os_mkdir_mock.assert_has_calls(os_mkdir_calls)
     create_symlink_mock.assert_has_calls(create_symlink_calls)
@@ -449,7 +475,24 @@ class TestMpacks(TestCase):
     download_mpack_mock.return_value = "/tmp/myservice.tar.gz"
     expand_mpack_mock.return_value = "mpacks/myservice-ambari-mpack-1.0.0.0"
     get_ambari_version_mock.return_value = "2.4.0.0"
-    """
+
+    os_path_exists_mock.side_effect = [True, True, True, True, True, True,
+                                       True, True, False, False, False, False,
+                                       True, True, True, False, True, True,
+                                       True, False]
+
+    get_ambari_properties_mock.return_value = configs
+    shutil_move_mock.return_value = True
+    os_path_isdir_mock.return_value = True
+
+    install_mpack(options)
+
+    stacks_directory = configs[serverConfiguration.STACK_LOCATION_KEY]
+    common_services_directory = 
configs[serverConfiguration.COMMON_SERVICES_PATH_PROPERTY]
+    mpacks_directory = 
configs[serverConfiguration.MPACKS_STAGING_PATH_PROPERTY]
+    mpacks_staging_directory = os.path.join(mpacks_directory, 
"myservice-ambari-mpack-1.0.0.0")
+    dashboards_directory = serverConfiguration.get_dashboard_location(configs)
+
     os_path_exists_calls = [call('/tmp/myservice.tar.gz'),
                             
call('mpacks/myservice-ambari-mpack-1.0.0.0/mpack.json'),
                             
call('/var/lib/ambari-server/resources/stacks/MYSTACK/1.0'),
@@ -458,31 +501,23 @@ class TestMpacks(TestCase):
                             
call('/var/lib/ambari-server/resources/common-services'),
                             call(mpacks_directory),
                             call(mpacks_directory + '/cache'),
+                            
call('/var/lib/ambari-server/resources/dashboards'),
                             call(mpacks_directory + 
'/myservice-ambari-mpack-1.0.0.0'),
                             
call('/var/lib/ambari-server/resources/common-services/MYSERVICE'),
+                            call(mpacks_directory + 
'/myservice-ambari-mpack-1.0.0.0/common-services/MYSERVICE/1.0.0/dashboards'),
                             
call('/var/lib/ambari-server/resources/stacks/MYSTACK'),
                             
call('/var/lib/ambari-server/resources/stacks/MYSTACK/1.0'),
                             
call('/var/lib/ambari-server/resources/stacks/MYSTACK/1.0/services'),
+                            call(mpacks_directory + 
'/myservice-ambari-mpack-1.0.0.0/custom-services/MYSERVICE/1.0.0/dashboards'),
                             
call('/var/lib/ambari-server/resources/stacks/MYSTACK'),
                             
call('/var/lib/ambari-server/resources/stacks/MYSTACK/2.0'),
-                            
call('/var/lib/ambari-server/resources/stacks/MYSTACK/2.0/services')]
-    """
-    os_path_exists_mock.side_effect = [True, True, True, True, True, True,
-                                       True, True, False, False, True,
-                                       True, True, True, True, True]
-
-    get_ambari_properties_mock.return_value = configs
-    shutil_move_mock.return_value = True
-    os_path_isdir_mock.return_value = True
-
-    install_mpack(options)
-
-    stacks_directory = configs[serverConfiguration.STACK_LOCATION_KEY]
-    common_services_directory = 
configs[serverConfiguration.COMMON_SERVICES_PATH_PROPERTY]
-    mpacks_directory = 
configs[serverConfiguration.MPACKS_STAGING_PATH_PROPERTY]
-    mpacks_staging_directory = os.path.join(mpacks_directory, 
"myservice-ambari-mpack-1.0.0.0")
+                            
call('/var/lib/ambari-server/resources/stacks/MYSTACK/2.0/services'),
+                            call(mpacks_directory + 
'/myservice-ambari-mpack-1.0.0.0/custom-services/MYSERVICE/2.0.0/dashboards')]
 
     os_mkdir_calls = [
+      call(dashboards_directory),
+      call(os.path.join(dashboards_directory, GRAFANA_DASHBOARDS_DIRNAME)),
+      call(os.path.join(dashboards_directory, SERVICE_METRICS_DIRNAME)),
       call(os.path.join(common_services_directory, "MYSERVICE"))
     ]
     create_symlink_calls = [
@@ -496,12 +531,14 @@ class TestMpacks(TestCase):
            os.path.join(stacks_directory, "MYSTACK/2.0/services/MYSERVICE"))
     ]
 
+    os_path_exists_mock.assert_has_calls(os_path_exists_calls)
     self.assertFalse(purge_stacks_and_mpacks_mock.called)
     os_mkdir_mock.assert_has_calls(os_mkdir_calls)
     create_symlink_mock.assert_has_calls(create_symlink_calls)
     os_symlink_mock.assert_has_calls(os_symlink_calls)
     self.assertTrue(add_replay_log_mock.called)
 
+  @patch("ambari_server.setupMpacks.create_symlink_using_path")
   @patch("os.path.exists")
   @patch("shutil.move")
   @patch("os.mkdir")
@@ -517,7 +554,7 @@ class TestMpacks(TestCase):
   def test_upgrade_stack_mpack(self, run_os_command_mock, download_mpack_mock, 
expand_mpack_mock, purge_stacks_and_mpacks_mock,
                                uninstall_mpack_mock, add_replay_log_mock, 
get_ambari_properties_mock,
                                get_ambari_version_mock, create_symlink_mock, 
os_mkdir_mock, shutil_move_mock,
-                               os_path_exists_mock):
+                               os_path_exists_mock, 
create_symlink_using_path_mock):
     options = self._create_empty_options_mock()
     options.mpack_path = "/path/to/mystack-1.0.0.1.tar.gz"
     download_mpack_mock.side_effect = ["/tmp/mystack-1.0.0.1.tar.gz", 
"/tmp/mystack-1.0.0.1.tar.gz"]
@@ -525,10 +562,27 @@ class TestMpacks(TestCase):
     get_ambari_version_mock.return_value = "2.4.0.0"
     run_os_command_mock.return_value = (0, "", "")
     mpacks_directory = 
configs[serverConfiguration.MPACKS_STAGING_PATH_PROPERTY]
-    """
+    os_path_exists_mock.side_effect = [True, True, True, True, True, True, 
True, True,
+                                       True, True, True, True, True, True, 
True, False,
+                                       False, True, False, False, True, False, 
False, 
+                                       False, False, False, True, True, True, 
False,
+                                       True, True, False, True, True, False, 
False,
+                                       False, False, False, True, True, True, 
True,
+                                       True, True, True, False, True, False, 
True, True, 
+                                       True, True, True, True]
+    get_ambari_properties_mock.return_value = configs
+    shutil_move_mock.return_value = True
+
+    upgrade_mpack(options)
+
+    stacks_directory = configs[serverConfiguration.STACK_LOCATION_KEY]
+    common_services_directory = 
configs[serverConfiguration.COMMON_SERVICES_PATH_PROPERTY]
+    mpacks_directory = 
configs[serverConfiguration.MPACKS_STAGING_PATH_PROPERTY]
+    mpacks_staging_directory = os.path.join(mpacks_directory, 
"mystack-ambari-mpack-1.0.0.1")
+    dashboards_directory = serverConfiguration.get_dashboard_location(configs)
+
     os_path_exists_calls = [call('/tmp/mystack-1.0.0.1.tar.gz'),
                             
call('mpacks/mystack-ambari-mpack-1.0.0.1/mpack.json'),
-                            
call('mpacks/mystack-ambari-mpack-1.0.0.1/hook/before_upgrade.py'),
                             call(mpacks_directory),
                             call(mpacks_directory + 
'/myextension-ambari-mpack-1.0.0.0/mpack.json'),
                             call(mpacks_directory + 
'/myservice-ambari-mpack-1.0.0.0/mpack.json'),
@@ -536,44 +590,53 @@ class TestMpacks(TestCase):
                             call(mpacks_directory + 
'/mystack-ambari-mpack-1.0.0.1/mpack.json'),
                             call('/tmp/mystack-1.0.0.1.tar.gz'),
                             
call('mpacks/mystack-ambari-mpack-1.0.0.1/mpack.json'),
+                            
call('mpacks/mystack-ambari-mpack-1.0.0.1/hooks/before_upgrade.py'),
                             call('/var/lib/ambari-server/resources/stacks'),
                             
call('/var/lib/ambari-server/resources/extensions'),
                             
call('/var/lib/ambari-server/resources/common-services'),
                             call(mpacks_directory),
                             call(mpacks_directory + '/cache'),
+                            
call('/var/lib/ambari-server/resources/dashboards'),
                             call(mpacks_directory + 
'/mystack-ambari-mpack-1.0.0.1'),
                             
call('/var/lib/ambari-server/resources/common-services/SERVICEA'),
+                            call(mpacks_directory + 
'/mystack-ambari-mpack-1.0.0.1/common-services/SERVICEA/1.0/dashboards'),
+                            call(mpacks_directory + 
'/mystack-ambari-mpack-1.0.0.1/common-services/SERVICEA/2.0/dashboards'),
                             
call('/var/lib/ambari-server/resources/common-services/SERVICEB'),
+                            call(mpacks_directory + 
'/mystack-ambari-mpack-1.0.0.1/common-services/SERVICEB/1.0.0/dashboards'),
+                            call(mpacks_directory + 
'/mystack-ambari-mpack-1.0.0.1/common-services/SERVICEB/2.0.0/dashboards'),
                             
call('/var/lib/ambari-server/resources/common-services/SERVICEC'),
+                            call(mpacks_directory + 
'/mystack-ambari-mpack-1.0.0.1/common-services/SERVICEC/1.0.0/dashboards'),
+                            call(mpacks_directory + 
'/mystack-ambari-mpack-1.0.0.1/common-services/SERVICEC/2.0.0/dashboards'),
                             
call('/var/lib/ambari-server/resources/stacks/MYSTACK'),
                             
call('/var/lib/ambari-server/resources/stacks/MYSTACK/1.0'),
                             
call('/var/lib/ambari-server/resources/stacks/MYSTACK/1.0/services'),
+                            call(mpacks_directory + 
'/mystack-ambari-mpack-1.0.0.1/stacks/MYSTACK/1.0/services/SERVICEA/dashboards'),
                             
call('/var/lib/ambari-server/resources/stacks/MYSTACK/1.1'),
                             
call('/var/lib/ambari-server/resources/stacks/MYSTACK/1.1/services'),
+                            call(mpacks_directory + 
'/mystack-ambari-mpack-1.0.0.1/stacks/MYSTACK/1.1/services/SERVICEA/dashboards'),
                             
call('/var/lib/ambari-server/resources/stacks/MYSTACK/2.0'),
-                            
call('/var/lib/ambari-server/resources/stacks/MYSTACK/2.0/services')]
+                            
call('/var/lib/ambari-server/resources/stacks/MYSTACK/2.0/services'),
+                            call(mpacks_directory + 
'/mystack-ambari-mpack-1.0.0.1/stacks/MYSTACK/2.0/services/SERVICEA/dashboards'),
+                            call(mpacks_directory + 
'/mystack-ambari-mpack-1.0.0.1/stacks/MYSTACK/2.0/services/SERVICEB/dashboards'),
                             
call('/var/lib/ambari-server/resources/stacks/MYSTACK/3.0'),
                             
call('/var/lib/ambari-server/resources/stacks/MYSTACK/3.0/services'),
+                            call(mpacks_directory + 
'/mystack-ambari-mpack-1.0.0.1/stacks/MYSTACK/3.0/services/SERVICEA/dashboards'),
+                            call(mpacks_directory + 
'/mystack-ambari-mpack-1.0.0.1/stacks/MYSTACK/3.0/services/SERVICEB/dashboards'),
+                            call(mpacks_directory + 
'/mystack-ambari-mpack-1.0.0.1/stacks/MYSTACK/3.0/services/SERVICEB/dashboards/grafana-dashboards'),
+                            
call('/var/lib/ambari-server/resources/dashboards/grafana-dashboards/SERVICEB'),
+                            call(mpacks_directory + 
'/mystack-ambari-mpack-1.0.0.1/stacks/MYSTACK/3.0/services/SERVICEB/dashboards/service-metrics/SERVICEB.txt'),
+                            
call('/var/lib/ambari-server/resources/dashboards/service-metrics/SERVICEB.txt'),
+                            call(mpacks_directory + 
'/mystack-ambari-mpack-1.0.0.1/stacks/MYSTACK/3.0/services/SERVICEC/dashboards'),
+                            call(mpacks_directory + 
'/mystack-ambari-mpack-1.0.0.1/stacks/MYSTACK/3.0/services/SERVICEC/dashboards/grafana-dashboards'),
+                            
call('/var/lib/ambari-server/resources/dashboards/grafana-dashboards/SERVICEC'),
+                            call(mpacks_directory + 
'/mystack-ambari-mpack-1.0.0.1/stacks/MYSTACK/3.0/services/SERVICEC/dashboards/service-metrics/SERVICEC.txt'),
+                            
call('/var/lib/ambari-server/resources/dashboards/service-metrics/SERVICEC.txt'),
                             call(mpacks_directory),
                             call(mpacks_directory + 
'/myextension-ambari-mpack-1.0.0.0/mpack.json'),
                             call(mpacks_directory + 
'/myservice-ambari-mpack-1.0.0.0/mpack.json'),
                             call(mpacks_directory + 
'/mystack-ambari-mpack-1.0.0.0/mpack.json'),
+                            call(mpacks_directory + 
'/mystack-ambari-mpack-1.0.0.1/mpack.json'),
                             call(mpacks_directory + 
'/mystack-ambari-mpack-1.0.0.1/hooks/after_upgrade.py')]
-    """
-    os_path_exists_mock.side_effect = [True, True, True, True, True, True, 
True, True,
-                                       True, True, True, True, True, True, 
True,
-                                       False, True, True, False, True, True, 
True,
-                                       True, True, True, True, False, False,
-                                       True, True, True, True, True, True]
-    get_ambari_properties_mock.return_value = configs
-    shutil_move_mock.return_value = True
-
-    upgrade_mpack(options)
-
-    stacks_directory = configs[serverConfiguration.STACK_LOCATION_KEY]
-    common_services_directory = 
configs[serverConfiguration.COMMON_SERVICES_PATH_PROPERTY]
-    mpacks_directory = 
configs[serverConfiguration.MPACKS_STAGING_PATH_PROPERTY]
-    mpacks_staging_directory = os.path.join(mpacks_directory, 
"mystack-ambari-mpack-1.0.0.1")
 
     run_os_command_calls = [
       call([
@@ -587,6 +650,9 @@ class TestMpacks(TestCase):
     ]
 
     os_mkdir_calls = [
+      call(dashboards_directory),
+      call(os.path.join(dashboards_directory, GRAFANA_DASHBOARDS_DIRNAME)),
+      call(os.path.join(dashboards_directory, SERVICE_METRICS_DIRNAME)),
       call(os.path.join(common_services_directory, "SERVICEC")),
       call(os.path.join(stacks_directory, "MYSTACK/3.0")),
       call(os.path.join(stacks_directory, "MYSTACK/3.0/services"))
@@ -642,13 +708,25 @@ class TestMpacks(TestCase):
            "SERVICEB", True),
       call(os.path.join(mpacks_staging_directory, 
"stacks/MYSTACK/3.0/services"),
            os.path.join(stacks_directory, "MYSTACK/3.0/services"),
-           "SERVICEC", True)
+           "SERVICEC", True),
+      call(os.path.join(mpacks_staging_directory, 
"stacks/MYSTACK/3.0/services/SERVICEC/dashboards/service-metrics"),
+           os.path.join(dashboards_directory, "service-metrics"),
+           "SERVICEC.txt", True)
     ]
 
+    create_symlink_using_path_calls = [
+      call(os.path.join(mpacks_staging_directory, 
"stacks/MYSTACK/3.0/services/SERVICEC/dashboards/grafana-dashboards"),
+           os.path.join(dashboards_directory, "grafana-dashboards/SERVICEC"), 
True)
+    ]
+
+    os_path_exists_mock.assert_has_calls(os_path_exists_calls)
     self.assertFalse(purge_stacks_and_mpacks_mock.called)
     run_os_command_mock.assert_has_calls(run_os_command_calls)
     os_mkdir_mock.assert_has_calls(os_mkdir_calls)
     create_symlink_mock.assert_has_calls(create_symlink_calls)
+    self.assertEqual(18, create_symlink_mock.call_count) 
+    
create_symlink_using_path_mock.assert_has_calls(create_symlink_using_path_calls)
+    self.assertEqual(1, create_symlink_using_path_mock.call_count)
     uninstall_mpack_mock.assert_has_calls([call("mystack-ambari-mpack", 
"1.0.0.0")])
     self.assertTrue(add_replay_log_mock.called)
 
@@ -684,6 +762,41 @@ class TestMpacks(TestCase):
     install_mpack_mock.assert_has_calls([call(install_replay_options, 
replay_mode=True)])
     upgrade_mpack_mock.assert_has_calls([call(upgrade_replay_options, 
replay_mode=True)])
 
+  @patch("resource_management.core.sudo.unlink")
+  @patch("resource_management.core.sudo.rmtree")
+  @patch("ambari_server.setupMpacks.get_ambari_version")
+  @patch("ambari_server.setupMpacks.get_ambari_properties")
+  def test_uninstall_mpack(self, get_ambari_properties_mock, 
get_ambari_version_mock, sudo_rmtree_mock, sudo_unlink_mock):
+    test_directory = os.path.dirname(os.path.abspath(__file__))
+    mpacks_directory = os.path.join(test_directory, "mpacks")
+    uninstall_directory = os.path.join(test_directory, "uninstall")
+    fake_configs = {
+      serverConfiguration.STACK_LOCATION_KEY : 
os.path.join(uninstall_directory, "stacks"),
+      serverConfiguration.COMMON_SERVICES_PATH_PROPERTY : 
os.path.join(uninstall_directory, "common-services"),
+      serverConfiguration.EXTENSION_PATH_PROPERTY : 
os.path.join(uninstall_directory, "extensions"),
+      serverConfiguration.MPACKS_STAGING_PATH_PROPERTY : mpacks_directory,
+      serverConfiguration.DASHBOARD_PATH_PROPERTY : 
os.path.join(uninstall_directory, "dashboards"),
+      serverConfiguration.SERVER_TMP_DIR_PROPERTY : "/tmp"
+    }
+
+    get_ambari_version_mock.return_value = "2.4.0.0"
+    get_ambari_properties_mock.return_value = fake_configs
+    stacks_directory = fake_configs[serverConfiguration.STACK_LOCATION_KEY]
+    extension_directory = 
fake_configs[serverConfiguration.EXTENSION_PATH_PROPERTY]
+    common_services_directory = 
fake_configs[serverConfiguration.COMMON_SERVICES_PATH_PROPERTY]
+    dashboard_directory = 
fake_configs[serverConfiguration.DASHBOARD_PATH_PROPERTY]
+
+    uninstall_mpack("mystack-ambari-mpack", "1.0.0.1")
+
+    self.assertEqual(1, sudo_rmtree_mock.call_count)
+    self.assertEqual(6, sudo_unlink_mock.call_count)
+    sudo_unlink_mock_calls = [call(os.path.join(stacks_directory, 
"2.0/SERVICEB")),
+                              call(os.path.join(stacks_directory, 
"2.0/files/metainfo2.xml")),
+                              call(os.path.join(extension_directory, 
"SERVICEB")),
+                              call(os.path.join(common_services_directory, 
"SERVICEB")),
+                              call(os.path.join(dashboard_directory, 
"SERVICEB")),
+                              call(os.path.join(dashboard_directory, 
"files/STORM.txt"))] 
+
   def _create_empty_options_mock(self):
     options = MagicMock()
     options.mpack_path = None

http://git-wip-us.apache.org/repos/asf/ambari/blob/4a7cbcb1/ambari-server/src/test/python/mpacks/mystack-ambari-mpack-1.0.0.1/stacks/MYSTACK/3.0/services/SERVICEC/dashboards/grafana-dashboards/grafana-hdfs-users.json
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/python/mpacks/mystack-ambari-mpack-1.0.0.1/stacks/MYSTACK/3.0/services/SERVICEC/dashboards/grafana-dashboards/grafana-hdfs-users.json
 
b/ambari-server/src/test/python/mpacks/mystack-ambari-mpack-1.0.0.1/stacks/MYSTACK/3.0/services/SERVICEC/dashboards/grafana-dashboards/grafana-hdfs-users.json
new file mode 100644
index 0000000..4aad145
--- /dev/null
+++ 
b/ambari-server/src/test/python/mpacks/mystack-ambari-mpack-1.0.0.1/stacks/MYSTACK/3.0/services/SERVICEC/dashboards/grafana-dashboards/grafana-hdfs-users.json
@@ -0,0 +1,270 @@
+{
+  "id": null,
+  "title": "HDFS - Users",
+  "originalTitle": "HDFS - Users",
+  "tags": [
+    "hdfs"
+  ],
+  "style": "dark",
+  "timezone": "browser",
+  "editable": true,
+  "hideControls": false,
+  "sharedCrosshair": false,
+  "rows": [
+    {
+      "collapse": false,
+      "editable": true,
+      "height": "25px",
+      "panels": [
+        {
+          "content": "<h4 align=\"center\">Metrics for HDFS Namenode RPC Call 
Queue status in terms of call volumes for top users and their priority 
assignment. Click on each row title to expand on demand to look at various 
metrics. </h4>\n<h5 align=\"center\">HDFS User metrics aren't emitted by 
default. You can use this <a style=\"color: green;\" 
href=\"https://cwiki.apache.org/confluence/display/AMBARI/Enabling+HDFS+per-user+Metrics\";>document</a>
 as a reference to enable them.</h5>\n<h6 style=\"color:red;\" 
align=\"center\">This dashboard is managed by Ambari.  You may lose any changes 
made to this dashboard.  If you want to customize, make your own copy.</h6>",
+          "editable": true,
+          "error": false,
+          "id": 3,
+          "isNew": true,
+          "links": [],
+          "mode": "html",
+          "span": 12,
+          "style": {},
+          "title": "",
+          "type": "text"
+        }
+      ],
+      "title": "New row"
+    },
+    {
+      "collapse": false,
+      "editable": true,
+      "height": "250px",
+      "panels": [
+        {
+          "aliasColors": {},
+          "bars": false,
+          "datasource": null,
+          "editable": true,
+          "error": false,
+          "fill": 1,
+          "grid": {
+            "leftLogBase": 1,
+            "leftMax": null,
+            "leftMin": 0,
+            "rightLogBase": 1,
+            "rightMax": null,
+            "rightMin": null,
+            "threshold1": null,
+            "threshold1Color": "rgba(216, 200, 27, 0.27)",
+            "threshold2": null,
+            "threshold2Color": "rgba(234, 112, 112, 0.22)"
+          },
+          "id": 1,
+          "isNew": true,
+          "legend": {
+            "avg": false,
+            "current": false,
+            "hideEmpty": true,
+            "max": false,
+            "min": false,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": true,
+          "linewidth": 2,
+          "links": [],
+          "nullPointMode": "connected",
+          "percentage": false,
+          "pointradius": 5,
+          "points": false,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "span": 12,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "aggregator": "avg",
+              "alias": "Volume",
+              "app": "namenode",
+              "downsampleAggregator": "avg",
+              "errors": {},
+              "hosts": "",
+              "metric": 
"ipc.client.org.apache.hadoop.ipc.DecayRpcScheduler.Caller(*).Volume",
+              "precision": "default",
+              "refId": "A",
+              "transform": "diff"
+            }
+          ],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "Namenode Rpc Caller Volume",
+          "tooltip": {
+            "shared": false,
+            "value_type": "cumulative"
+          },
+          "type": "graph",
+          "x-axis": true,
+          "y-axis": true,
+          "y_formats": [
+            "short",
+            "short"
+          ]
+        }
+      ],
+      "title": "Row"
+    },
+    {
+      "collapse": false,
+      "editable": true,
+      "height": "250px",
+      "panels": [
+        {
+          "aliasColors": {},
+          "bars": false,
+          "datasource": null,
+          "editable": true,
+          "error": false,
+          "fill": 1,
+          "grid": {
+            "leftLogBase": 1,
+            "leftMax": null,
+            "leftMin": null,
+            "rightLogBase": 1,
+            "rightMax": null,
+            "rightMin": null,
+            "threshold1": null,
+            "threshold1Color": "rgba(216, 200, 27, 0.27)",
+            "threshold2": null,
+            "threshold2Color": "rgba(234, 112, 112, 0.22)"
+          },
+          "id": 2,
+          "isNew": true,
+          "legend": {
+            "avg": false,
+            "current": false,
+            "hideEmpty": true,
+            "hideZero": false,
+            "max": false,
+            "min": false,
+            "show": true,
+            "total": false,
+            "values": false
+          },
+          "lines": false,
+          "linewidth": 2,
+          "links": [],
+          "nullPointMode": "connected",
+          "percentage": false,
+          "pointradius": 3,
+          "points": true,
+          "renderer": "flot",
+          "seriesOverrides": [],
+          "span": 12,
+          "stack": false,
+          "steppedLine": false,
+          "targets": [
+            {
+              "aggregator": "avg",
+              "app": "namenode",
+              "downsampleAggregator": "avg",
+              "errors": {},
+              "metric": 
"ipc.client.org.apache.hadoop.ipc.DecayRpcScheduler.Caller(*).Priority",
+              "precision": "default",
+              "refId": "A",
+              "transform": "none"
+            }
+          ],
+          "timeFrom": null,
+          "timeShift": null,
+          "title": "Namenode Rpc Caller Priority",
+          "tooltip": {
+            "shared": false,
+            "value_type": "cumulative"
+          },
+          "type": "graph",
+          "x-axis": true,
+          "y-axis": true,
+          "y_formats": [
+            "short",
+            "short"
+          ]
+        }
+      ],
+      "title": "New row"
+    }
+  ],
+  "time": {
+    "from": "now-6h",
+    "to": "now"
+  },
+  "timepicker": {
+    "now": true,
+    "refresh_intervals": [
+      "5s",
+      "10s",
+      "30s",
+      "1m",
+      "5m",
+      "15m",
+      "30m",
+      "1h",
+      "2h",
+      "1d"
+    ],
+    "time_options": [
+      "5m",
+      "15m",
+      "1h",
+      "6h",
+      "12h",
+      "24h",
+      "2d",
+      "7d",
+      "30d"
+    ]
+  },
+  "templating": {
+    "list": [
+      {
+        "allFormat": "glob",
+        "current": {
+          "text": "All",
+          "value": ""
+        },
+        "datasource": null,
+        "hideLabel": false,
+        "includeAll": true,
+        "multi": true,
+        "multiFormat": "glob",
+        "name": "Callers",
+        "options": [
+          {
+            "text": "All",
+            "value": "",
+            "selected": true
+          }
+        ],
+        "query": "callers",
+        "refresh": true,
+        "regex": "",
+        "type": "query"
+      }
+    ]
+  },
+  "annotations": {
+    "list": []
+  },
+  "refresh": false,
+  "schemaVersion": 8,
+  "version": 27,
+  "links": [
+    {
+      "asDropdown": true,
+      "icon": "external link",
+      "tags": [
+        "hdfs"
+      ],
+      "title": "HDFS Dashboards",
+      "type": "dashboards"
+    }
+  ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/4a7cbcb1/ambari-server/src/test/python/mpacks/mystack-ambari-mpack-1.0.0.1/stacks/MYSTACK/3.0/services/SERVICEC/dashboards/service-metrics/STORM.txt
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/python/mpacks/mystack-ambari-mpack-1.0.0.1/stacks/MYSTACK/3.0/services/SERVICEC/dashboards/service-metrics/STORM.txt
 
b/ambari-server/src/test/python/mpacks/mystack-ambari-mpack-1.0.0.1/stacks/MYSTACK/3.0/services/SERVICEC/dashboards/service-metrics/STORM.txt
new file mode 100644
index 0000000..04bca00
--- /dev/null
+++ 
b/ambari-server/src/test/python/mpacks/mystack-ambari-mpack-1.0.0.1/stacks/MYSTACK/3.0/services/SERVICEC/dashboards/service-metrics/STORM.txt
@@ -0,0 +1,7 @@
+Supervisors
+Total Tasks
+Total Slots
+Used Slots
+Topologies
+Total Executors
+Free Slots

http://git-wip-us.apache.org/repos/asf/ambari/blob/4a7cbcb1/ambari-server/src/test/python/uninstall/common-services/SERVICEA
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/python/uninstall/common-services/SERVICEA 
b/ambari-server/src/test/python/uninstall/common-services/SERVICEA
new file mode 120000
index 0000000..b959028
--- /dev/null
+++ b/ambari-server/src/test/python/uninstall/common-services/SERVICEA
@@ -0,0 +1 @@
+../../mpacks/mystack-ambari-mpack-1.0.0.0/stacks/MYSTACK/1.0/services/SERVICEA
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/4a7cbcb1/ambari-server/src/test/python/uninstall/common-services/SERVICEB
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/python/uninstall/common-services/SERVICEB 
b/ambari-server/src/test/python/uninstall/common-services/SERVICEB
new file mode 120000
index 0000000..99609ca
--- /dev/null
+++ b/ambari-server/src/test/python/uninstall/common-services/SERVICEB
@@ -0,0 +1 @@
+../../mpacks/mystack-ambari-mpack-1.0.0.1/stacks/MYSTACK/2.0/services/SERVICEB
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/4a7cbcb1/ambari-server/src/test/python/uninstall/dashboards/SERVICEA
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/python/uninstall/dashboards/SERVICEA 
b/ambari-server/src/test/python/uninstall/dashboards/SERVICEA
new file mode 120000
index 0000000..b959028
--- /dev/null
+++ b/ambari-server/src/test/python/uninstall/dashboards/SERVICEA
@@ -0,0 +1 @@
+../../mpacks/mystack-ambari-mpack-1.0.0.0/stacks/MYSTACK/1.0/services/SERVICEA
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/4a7cbcb1/ambari-server/src/test/python/uninstall/dashboards/SERVICEB
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/python/uninstall/dashboards/SERVICEB 
b/ambari-server/src/test/python/uninstall/dashboards/SERVICEB
new file mode 120000
index 0000000..99609ca
--- /dev/null
+++ b/ambari-server/src/test/python/uninstall/dashboards/SERVICEB
@@ -0,0 +1 @@
+../../mpacks/mystack-ambari-mpack-1.0.0.1/stacks/MYSTACK/2.0/services/SERVICEB
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/4a7cbcb1/ambari-server/src/test/python/uninstall/dashboards/files/README.txt
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/python/uninstall/dashboards/files/README.txt 
b/ambari-server/src/test/python/uninstall/dashboards/files/README.txt
new file mode 100644
index 0000000..f1775e0
--- /dev/null
+++ b/ambari-server/src/test/python/uninstall/dashboards/files/README.txt
@@ -0,0 +1,17 @@
+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.
+
+Real file

http://git-wip-us.apache.org/repos/asf/ambari/blob/4a7cbcb1/ambari-server/src/test/python/uninstall/dashboards/files/STORM.txt
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/python/uninstall/dashboards/files/STORM.txt 
b/ambari-server/src/test/python/uninstall/dashboards/files/STORM.txt
new file mode 120000
index 0000000..a235e5b
--- /dev/null
+++ b/ambari-server/src/test/python/uninstall/dashboards/files/STORM.txt
@@ -0,0 +1 @@
+../../../mpacks/mystack-ambari-mpack-1.0.0.1/stacks/MYSTACK/3.0/services/SERVICEC/dashboards/service-metrics/STORM.txt
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/4a7cbcb1/ambari-server/src/test/python/uninstall/dashboards/files/metainfo.xml
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/python/uninstall/dashboards/files/metainfo.xml 
b/ambari-server/src/test/python/uninstall/dashboards/files/metainfo.xml
new file mode 120000
index 0000000..dd1cc28
--- /dev/null
+++ b/ambari-server/src/test/python/uninstall/dashboards/files/metainfo.xml
@@ -0,0 +1 @@
+../../../mpacks/mystack-ambari-mpack-1.0.0.0/stacks/MYSTACK/2.0/metainfo.xml
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/4a7cbcb1/ambari-server/src/test/python/uninstall/extensions/SERVICEA
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/python/uninstall/extensions/SERVICEA 
b/ambari-server/src/test/python/uninstall/extensions/SERVICEA
new file mode 120000
index 0000000..b959028
--- /dev/null
+++ b/ambari-server/src/test/python/uninstall/extensions/SERVICEA
@@ -0,0 +1 @@
+../../mpacks/mystack-ambari-mpack-1.0.0.0/stacks/MYSTACK/1.0/services/SERVICEA
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/4a7cbcb1/ambari-server/src/test/python/uninstall/extensions/SERVICEB
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/python/uninstall/extensions/SERVICEB 
b/ambari-server/src/test/python/uninstall/extensions/SERVICEB
new file mode 120000
index 0000000..99609ca
--- /dev/null
+++ b/ambari-server/src/test/python/uninstall/extensions/SERVICEB
@@ -0,0 +1 @@
+../../mpacks/mystack-ambari-mpack-1.0.0.1/stacks/MYSTACK/2.0/services/SERVICEB
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/4a7cbcb1/ambari-server/src/test/python/uninstall/stacks/2.0/SERVICEA
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/python/uninstall/stacks/2.0/SERVICEA 
b/ambari-server/src/test/python/uninstall/stacks/2.0/SERVICEA
new file mode 120000
index 0000000..39f34f6
--- /dev/null
+++ b/ambari-server/src/test/python/uninstall/stacks/2.0/SERVICEA
@@ -0,0 +1 @@
+../../../mpacks/mystack-ambari-mpack-1.0.0.0/stacks/MYSTACK/1.0/services/SERVICEA
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/4a7cbcb1/ambari-server/src/test/python/uninstall/stacks/2.0/SERVICEB
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/python/uninstall/stacks/2.0/SERVICEB 
b/ambari-server/src/test/python/uninstall/stacks/2.0/SERVICEB
new file mode 120000
index 0000000..83677ca
--- /dev/null
+++ b/ambari-server/src/test/python/uninstall/stacks/2.0/SERVICEB
@@ -0,0 +1 @@
+../../../mpacks/mystack-ambari-mpack-1.0.0.1/stacks/MYSTACK/2.0/services/SERVICEB
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/4a7cbcb1/ambari-server/src/test/python/uninstall/stacks/2.0/files/README.txt
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/python/uninstall/stacks/2.0/files/README.txt 
b/ambari-server/src/test/python/uninstall/stacks/2.0/files/README.txt
new file mode 100644
index 0000000..f1775e0
--- /dev/null
+++ b/ambari-server/src/test/python/uninstall/stacks/2.0/files/README.txt
@@ -0,0 +1,17 @@
+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.
+
+Real file

http://git-wip-us.apache.org/repos/asf/ambari/blob/4a7cbcb1/ambari-server/src/test/python/uninstall/stacks/2.0/files/metainfo1.xml
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/python/uninstall/stacks/2.0/files/metainfo1.xml 
b/ambari-server/src/test/python/uninstall/stacks/2.0/files/metainfo1.xml
new file mode 120000
index 0000000..da62332
--- /dev/null
+++ b/ambari-server/src/test/python/uninstall/stacks/2.0/files/metainfo1.xml
@@ -0,0 +1 @@
+../../../../mpacks/mystack-ambari-mpack-1.0.0.0/stacks/MYSTACK/1.0/metainfo.xml
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/4a7cbcb1/ambari-server/src/test/python/uninstall/stacks/2.0/files/metainfo2.xml
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/test/python/uninstall/stacks/2.0/files/metainfo2.xml 
b/ambari-server/src/test/python/uninstall/stacks/2.0/files/metainfo2.xml
new file mode 120000
index 0000000..2316e88
--- /dev/null
+++ b/ambari-server/src/test/python/uninstall/stacks/2.0/files/metainfo2.xml
@@ -0,0 +1 @@
+../../../../mpacks/mystack-ambari-mpack-1.0.0.1/stacks/MYSTACK/1.0/metainfo.xml
\ No newline at end of file

Reply via email to