This is an automated email from the ASF dual-hosted git repository.

dsen pushed a commit to branch branch-feature-AMBARI-14714
in repository https://gitbox.apache.org/repos/asf/ambari.git

commit 998d453cf5fa507e2cde85bc963b67e461a7561a
Author: Dmytro Sen <d...@apache.org>
AuthorDate: Thu Feb 15 19:58:38 2018 +0200

    [AMBARI-23004] Create initial version of InstanceManager to create instance 
layout (dsen)
---
 ambari-agent/conf/unix/ambari-agent                |   2 +-
 ambari-agent/conf/unix/install-helper.sh           |   2 +-
 mpack-instance-manager/pom.xml                     | 253 +++++++++++
 .../src/main/package/deb/control/control           |  22 +
 .../src/main/package/deb/control/postinst          |  25 ++
 .../src/main/package/deb/control/prerm             |  29 ++
 .../src/main/package/rpm/postinstall.sh            |  24 +
 .../src/main/package/rpm/preremove.sh              |  28 ++
 .../python/instance_manager/instance_manager.py    | 500 +++++++++++++++++++++
 .../instance_manager/mpack-instance-manager.py     | 138 ++++++
 .../src/packages/tarball/all.xml                   |  37 ++
 .../instance_manager/test_instance_manager.py      | 265 +++++++++++
 .../src/test/python/unitTests.py                   | 129 ++++++
 pom.xml                                            |   4 +
 14 files changed, 1456 insertions(+), 2 deletions(-)

diff --git a/ambari-agent/conf/unix/ambari-agent 
b/ambari-agent/conf/unix/ambari-agent
index 8168002..0254484 100755
--- a/ambari-agent/conf/unix/ambari-agent
+++ b/ambari-agent/conf/unix/ambari-agent
@@ -62,7 +62,7 @@ export PATH=/usr/sbin:/sbin:/usr/lib/ambari-server/*:$PATH
 export AMBARI_CONF_DIR=$HOME_DIR/etc/ambari-server/conf:$PATH
 
 # Because Ambari rpm unpacks modules here on all systems
-export PYTHONPATH=/usr/lib/ambari-agent/lib:${PYTHONPATH:-}
+export 
PYTHONPATH=/usr/lib/ambari-agent/lib:/usr/lib/mpack-instance-manager:${PYTHONPATH:-}
 
 export AMBARI_PID_DIR=`get_agent_property piddir`
 export AMBARI_PID_DIR=`valid_path "${AMBARI_PID_DIR:?}"`
diff --git a/ambari-agent/conf/unix/install-helper.sh 
b/ambari-agent/conf/unix/install-helper.sh
index e305866..7c4de80 100644
--- a/ambari-agent/conf/unix/install-helper.sh
+++ b/ambari-agent/conf/unix/install-helper.sh
@@ -117,7 +117,7 @@ do_install(){
   fi
 
   if [ -f "$AMBARI_ENV_RPMSAVE" ] ; then
-    PYTHON_PATH_LINE='export PYTHONPATH=/usr/lib/ambari-agent/lib:$PYTHONPATH'
+    PYTHON_PATH_LINE='export 
PYTHONPATH=/usr/lib/ambari-agent/lib:/usr/lib/mpack-instance-manager:$PYTHONPATH'
     grep "^$PYTHON_PATH_LINE\$" "$AMBARI_ENV_RPMSAVE" > /dev/null
     if [ $? -ne 0 ] ; then
       echo -e "\n$PYTHON_PATH_LINE" >> $AMBARI_ENV_RPMSAVE
diff --git a/mpack-instance-manager/pom.xml b/mpack-instance-manager/pom.xml
new file mode 100644
index 0000000..3ca6dd4
--- /dev/null
+++ b/mpack-instance-manager/pom.xml
@@ -0,0 +1,253 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <!--
+     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.
+    -->
+    <parent>
+        <groupId>org.apache.ambari</groupId>
+        <artifactId>ambari-project</artifactId>
+        <version>2.0.0.0-SNAPSHOT</version>
+        <relativePath>../ambari-project</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>org.apache.ambari</groupId>
+    <artifactId>mpack-instance-manager</artifactId>
+    <version>2.0.0.0-SNAPSHOT</version>
+    <name>Mpack instance manager</name>
+    <description>Mpack instance manager</description>
+    <properties>
+        
<instanceManagerInstallDir>/usr/lib/mpack-instance-manager</instanceManagerInstallDir>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <final.name>${project.artifactId}-${project.version}</final.name>
+        <package.release>1</package.release>
+        <package.prefix>/usr</package.prefix>
+        <skipTests>false</skipTests>
+        <deb.architecture>amd64</deb.architecture>
+        <target.cache.dir>${project.build.directory}/cache/</target.cache.dir>
+        <python.test.mask>[Tt]est*.py</python.test.mask>
+    </properties>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <version>1.8</version>
+                <executions>
+                    <execution>
+                        <id>parse-version</id>
+                        <phase>validate</phase>
+                        <goals>
+                            <goal>parse-version</goal>
+                        </goals>
+                    </execution>
+                    <execution>
+                        <id>regex-property</id>
+                        <goals>
+                            <goal>regex-property</goal>
+                        </goals>
+                        <configuration>
+                            <name>ambariVersion</name>
+                            <value>${project.version}</value>
+                            
<regex>^([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)(\.|-).*</regex>
+                            <replacement>$1.$2.$3.$4</replacement>
+                            <failIfNoMatch>false</failIfNoMatch>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>exec-maven-plugin</artifactId>
+                <version>1.2.1</version>
+                <executions>
+                    <execution>
+                        <configuration>
+                            <executable>${executable.python}</executable>
+                            
<workingDirectory>src/test/python</workingDirectory>
+                            <arguments>
+                                <argument>unitTests.py</argument>
+                            </arguments>
+                            <environmentVariables>
+                                
<PYTHONPATH>../../main/python:$PYTHONPATH</PYTHONPATH>
+                            </environmentVariables>
+                            <skip>${skipTests}</skip>
+                        </configuration>
+                        <id>python-test</id>
+                        <phase>test</phase>
+                        <goals>
+                            <goal>exec</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>rpm-maven-plugin</artifactId>
+                <version>2.1.4</version>
+                <executions>
+                    <execution>
+                        <!-- unbinds rpm creation from maven lifecycle -->
+                        <phase>none</phase>
+                        <goals>
+                            <goal>rpm</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                <configuration>
+
+                    <copyright>2012, Apache Software Foundation</copyright>
+                    <group>Development</group>
+                    <description>Maven Recipe: RPM Package.</description>
+                    <postinstallScriptlet>
+                        
<scriptFile>src/main/package/rpm/postinstall.sh</scriptFile>
+                        <fileEncoding>utf-8</fileEncoding>
+                    </postinstallScriptlet>
+                    <preremoveScriptlet>
+                        
<scriptFile>src/main/package/rpm/preremove.sh</scriptFile>
+                        <fileEncoding>utf-8</fileEncoding>
+                    </preremoveScriptlet>
+
+                    <needarch>x86_64</needarch>
+                    <autoRequires>false</autoRequires>
+                    <mappings>
+                        <mapping>
+                            <directory>${instanceManagerInstallDir}</directory>
+                            <filemode>755</filemode>
+                            <username>root</username>
+                            <groupname>root</groupname>
+                            <sources>
+                                <source>
+                                    <location>
+                                        
${project.build.directory}${dirsep}${project.artifactId}-${project.version}${instanceManagerInstallDir}
+                                    </location>
+                                </source>
+                            </sources>
+                        </mapping>
+                    </mappings>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.vafer</groupId>
+                <artifactId>jdeb</artifactId>
+                <version>1.4</version>
+                <executions>
+                    <execution>
+                        <phase>none</phase>
+                        <goals>
+                            <goal>jdeb</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                <configuration>
+                    
<controlDir>${basedir}/src/main/package/deb/control</controlDir>
+                    
<deb>${basedir}/target/${project.artifactId}_${package-version}-${package-release}.deb</deb>
+                    <skip>false</skip>
+                    <skipPOMs>false</skipPOMs>
+                    <dataSet>
+                        <data>
+                            
<src>${project.build.directory}${dirsep}${project.artifactId}-${project.version}.tar.gz
+                            </src>
+                            <type>archive</type>
+                            <mapper>
+                                <type>perm</type>
+                                <user>root</user>
+                                <group>root</group>
+                            </mapper>
+                        </data>
+                    </dataSet>
+                </configuration>
+            </plugin>
+            <plugin>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <configuration>
+                    <tarLongFileMode>gnu</tarLongFileMode>
+                    <descriptors>
+                        <descriptor>src/packages/tarball/all.xml</descriptor>
+                    </descriptors>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>make-assembly</id>
+                        <phase>${assemblyPhase}</phase>
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.rat</groupId>
+                <artifactId>apache-rat-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <phase>test</phase>
+                        <goals>
+                            <goal>check</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>buildnumber-maven-plugin</artifactId>
+                <version>${buildnumber-maven-plugin-version}</version>
+                <configuration>
+                    
<urlScm>scm:git:https://git-wip-us.apache.org/repos/asf/incubator-ambari.git</urlScm>
+                </configuration>
+                <executions>
+                    <execution>
+                        <phase>validate</phase>
+                        <goals>
+                            <goal>create</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+        <extensions>
+            <extension>
+                <groupId>org.apache.maven.wagon</groupId>
+                <artifactId>wagon-ssh-external</artifactId>
+            </extension>
+        </extensions>
+    </build>
+    <profiles>
+        <profile>
+            <id>linux</id>
+            <activation>
+                <os>
+                    <family>unix</family>
+                </os>
+            </activation>
+            <properties>
+                <envClassifier>linux</envClassifier>
+                <dirsep>/</dirsep>
+                <pathsep>:</pathsep>
+                
<executable.python>${project.basedir}/../ambari-common/src/main/unix/ambari-python-wrap
+                </executable.python>
+                <executable.shell>sh</executable.shell>
+                <fileextension.shell>sh</fileextension.shell>
+                
<fileextension.dot.shell-default></fileextension.dot.shell-default>
+                <path.python.1>
+                    
${project.basedir}/../ambari-common/src/main/python:${project.basedir}/../ambari-agent/src/main/python:${project.basedir}/../ambari-common/src/main/python/ambari_jinja2:${project.basedir}/../ambari-common/src/main/python/ambari_commons:${project.basedir}/../ambari-common/src/test/python:${project.basedir}/src/main/python:${project.basedir}/src/main/python/ambari_agent:${project.basedir}/src/main/python/resource_management:${project.basedir}/src/test/python:${project.b
 [...]
+                </path.python.1>
+            </properties>
+        </profile>
+    </profiles>
+</project>
\ No newline at end of file
diff --git a/mpack-instance-manager/src/main/package/deb/control/control 
b/mpack-instance-manager/src/main/package/deb/control/control
new file mode 100644
index 0000000..2ea34a5
--- /dev/null
+++ b/mpack-instance-manager/src/main/package/deb/control/control
@@ -0,0 +1,22 @@
+# 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
+Package: [[artifactId]]
+Version: [[package-version]]-[[package-release]]
+Section: [[deb.section]]
+Priority: [[deb.priority]]
+Depends: [[deb.dependency.list]]
+Architecture: [[deb.architecture]]
+Description: [[description]]
+Maintainer: [[deb.publisher]]
\ No newline at end of file
diff --git a/mpack-instance-manager/src/main/package/deb/control/postinst 
b/mpack-instance-manager/src/main/package/deb/control/postinst
new file mode 100644
index 0000000..e520da4
--- /dev/null
+++ b/mpack-instance-manager/src/main/package/deb/control/postinst
@@ -0,0 +1,25 @@
+#!/bin/bash
+# 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
+
+MPACK_INSTANCE_MANAGER_BINARY="/usr/lib/mpack-instance-manager/mpack-instance-manager.py"
+MPACK_INSTANCE_MANAGER_BINARY_SYMLINK="/usr/sbin/mpack-instance-manager"
+
+# setting mpack-instance-manager binary symlink
+if [ ! -f "$MPACK_INSTANCE_MANAGER_BINARY_SYMLINK" ]; then
+  ln -s "$MPACK_INSTANCE_MANAGER_BINARY" 
"$MPACK_INSTANCE_MANAGER_BINARY_SYMLINK"
+fi
+
+exit 0
\ No newline at end of file
diff --git a/mpack-instance-manager/src/main/package/deb/control/prerm 
b/mpack-instance-manager/src/main/package/deb/control/prerm
new file mode 100644
index 0000000..5b36d4e
--- /dev/null
+++ b/mpack-instance-manager/src/main/package/deb/control/prerm
@@ -0,0 +1,29 @@
+#!/bin/bash
+# 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
+
+# WARNING: This script is performed not only on uninstall, but also
+# during package update. See http://www.ibm.com/developerworks/library/l-rpm2/
+# for details
+
+MPACK_INSTANCE_MANAGER_BINARY_SYMLINK="/usr/sbin/mpack-instance-manager"
+
+if [ "$1" -eq 0 ]; then  # Action is uninstall
+    if [ -f "$MPACK_INSTANCE_MANAGER_BINARY_SYMLINK" ]; then
+      rm -f "$MPACK_INSTANCE_MANAGER_BINARY_SYMLINK"
+    fi
+fi
+
+exit 0
\ No newline at end of file
diff --git a/mpack-instance-manager/src/main/package/rpm/postinstall.sh 
b/mpack-instance-manager/src/main/package/rpm/postinstall.sh
new file mode 100644
index 0000000..d94ca60
--- /dev/null
+++ b/mpack-instance-manager/src/main/package/rpm/postinstall.sh
@@ -0,0 +1,24 @@
+# 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
+
+MPACK_INSTANCE_MANAGER_BINARY="/usr/lib/mpack-instance-manager/mpack-instance-manager.py"
+MPACK_INSTANCE_MANAGER_BINARY_SYMLINK="/usr/sbin/mpack-instance-manager"
+
+# setting mpack-instance-manager binary symlink
+if [ ! -f "$MPACK_INSTANCE_MANAGER_BINARY_SYMLINK" ]; then
+  ln -s "$MPACK_INSTANCE_MANAGER_BINARY" 
"$MPACK_INSTANCE_MANAGER_BINARY_SYMLINK"
+fi
+
+exit 0
\ No newline at end of file
diff --git a/mpack-instance-manager/src/main/package/rpm/preremove.sh 
b/mpack-instance-manager/src/main/package/rpm/preremove.sh
new file mode 100644
index 0000000..7101a02
--- /dev/null
+++ b/mpack-instance-manager/src/main/package/rpm/preremove.sh
@@ -0,0 +1,28 @@
+# 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
+
+# WARNING: This script is performed not only on uninstall, but also
+# during package update. See http://www.ibm.com/developerworks/library/l-rpm2/
+# for details
+
+MPACK_INSTANCE_MANAGER_BINARY_SYMLINK="/usr/sbin/mpack-instance-manager"
+
+if [ "$1" -eq 0 ]; then  # Action is uninstall
+    if [ -f "$MPACK_INSTANCE_MANAGER_BINARY_SYMLINK" ]; then
+      rm -f "$MPACK_INSTANCE_MANAGER_BINARY_SYMLINK"
+    fi
+fi
+
+exit 0
\ No newline at end of file
diff --git 
a/mpack-instance-manager/src/main/python/instance_manager/instance_manager.py 
b/mpack-instance-manager/src/main/python/instance_manager/instance_manager.py
new file mode 100644
index 0000000..6f27ebc
--- /dev/null
+++ 
b/mpack-instance-manager/src/main/python/instance_manager/instance_manager.py
@@ -0,0 +1,500 @@
+"""
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+"""
+
+__all__ = ["create_mpack", "set_mpack_instance", "get_conf_dir", 
"list_instances"]
+
+import sys
+import os
+import json
+
+MPACK_JSON_FILE_NAME = 'mpack.json'
+CURRENT_SOFTLINK_NAME = 'current'
+CONFIGS_DIRECTORY_NAME = 'conf'
+
+ROOT_FOLDER_PATH = "/opt/odp"
+
+INSTANCES_FOLDER_NAME = "instances"
+MODULES_FOLDER_NAME = "modules"
+MPACKS_FOLDER_NAME = "mpacks"
+DEFAULT_COMPONENT_INSTANCE_NAME = 'default'
+DEFAULT_MPACK_INSTANCE_NAME = 'default'
+
+
+def create_mpack(mpack_name, mpack_version, mpack_instance, subgroup_name, 
module_name,
+                 components=None, components_map=None):
+  """
+  Use case 1: Creates an instance of mpack with a new subgroup, new module and 
one or more component(s)
+
+  Use case 2: Creates/adds in an existing mpack either a : new subgroup and/or 
module and/or component instance.
+
+  Components are provided as map with key as 'component type' and value as 
'list of individual component instances
+  names' OR empty map to create single instance of all components with name 
'default'
+  OR
+  list of 'components_instances_name' to be created. (default) OR '*' for all 
components
+  """
+  MpackInstance.create_mpack_instance(mpack_name, mpack_version, 
mpack_instance, subgroup_name, module_name,
+                                      components, components_map)
+
+
+def set_mpack_instance(mpack, mpack_version, mpack_instance, subgroup_name, 
module_name,
+                       components=None, components_map=None):
+  """
+  Use case: move a given component instances from one version to the next 
version by modifying the soft links.
+  Eg: Moving hive_server instance 'HS-1' from version 1.0.0-b1 to 1.5.0-b1.
+
+  Components are provided as map with key as 'component type' and value as 
'list of individual component instances
+  names' OR empty map to create single instance of all components with name 
'default'
+  OR
+  list of 'components_instances_name' to be created. (default) OR '*' for all 
components
+  """
+  instances = 
MpackInstance.parse_instances_with_filtering(os.path.join(ROOT_FOLDER_PATH, 
INSTANCES_FOLDER_NAME), mpack,
+                                                           mpack_instance, 
subgroup_name, module_name,
+                                                           components, 
components_map)
+  if not instances:
+    print("\nFound no instances for the given filters.")
+    sys.exit(0)
+
+  for mpack in instances:
+    for mpack_instance_name in instances[mpack]:
+      instances[mpack][mpack_instance_name].set_new_version(mpack, 
mpack_version)
+
+
+def get_conf_dir(mpack=None, mpack_instance=None, subgroup_name='default', 
module_name=None, components_map=None):
+  """
+  Use case: retrieve conf directory paths for a given component instances 
based on the granularity specified
+            ranging from: mpack, mpack-instance, subgroup-name, module-name 
and map of component instance
+            AND with a filtering on each level
+
+  Granularity works only while names for all consecutive levels are specified.
+  Levels: mpack/instance/subgroup/module
+  E.g If only mpack and subgroup names are specified, the granularity will 
work only on mpack level,
+      though the subgroup filer will be applied. But if the instance name is 
specified also, than only granular output
+      of subgroup will be returned.
+
+  Components are provided as map with key as 'component type' and value as 
'list of individual component instances
+  names' OR empty map for all component instances present
+  """
+  return parse_mpack_instances_with_filtering(mpack, mpack_instance, 
subgroup_name, module_name, components_map,
+                                              output_conf_dir=True)
+
+
+def list_instances(mpack=None, mpack_instance=None, subgroup_name='default', 
module_name=None, components_map=None):
+  """
+  Use case: figure out the versions a given component instances based on the 
granularity specified
+            ranging from: mpack, mpack-instance, subgroup-name, module-name 
and map of component instance
+            AND with a filtering on each level
+
+  Granularity works only while names for all consecutive levels are specified.
+  Levels: mpack/instance/subgroup/module
+  E.g If only mpack and subgroup names are specified, the granularity will 
work only on mpack level,
+      though the subgroup filer will be applied. But if the instance name is 
specified also, than only granular output
+      of subgroup will be returned.
+
+  Components are provided as map with key as 'component type' and value as 
'list of individual component instances
+  names' OR empty map for all component instances present
+  """
+  return parse_mpack_instances_with_filtering(mpack, mpack_instance, 
subgroup_name, module_name, components_map,
+                                              output_path=True)
+
+
+def parse_mpack_instances_with_filtering(mpack_name_filter, 
instance_name_filter, subgroup_name_filter,
+                                         module_name_filter, 
components_name_filter_map, output_conf_dir=False,
+                                         output_path=False):
+  instances = 
MpackInstance.parse_instances_with_filtering(os.path.join(ROOT_FOLDER_PATH, 
INSTANCES_FOLDER_NAME),
+                                                           mpack_name_filter,
+                                                           
instance_name_filter, subgroup_name_filter,
+                                                           module_name_filter,
+                                                           
components_name_filter_map)
+  full_json_output = build_json_output(instances, 
output_conf_dir=output_conf_dir, output_path=output_path)
+
+  granular_json_output = build_granular_output(full_json_output, 
mpack_name_filter, instance_name_filter,
+                                               subgroup_name_filter,
+                                               module_name_filter)
+
+  return granular_json_output
+
+
+def build_granular_output(json_output, mpack_name_filter, 
instance_name_filter, subgroup_name_filter,
+                          module_name_filter):
+  if mpack_name_filter:
+    json_output = json_output['mpacks'][mpack_name_filter]
+    if instance_name_filter:
+      json_output = 
json_output[MpackInstance.plural_name][instance_name_filter]
+      if subgroup_name_filter:
+        json_output = json_output['subgroups'][subgroup_name_filter]
+        if module_name_filter:
+          json_output = 
json_output[ModuleInstance.plural_name][module_name_filter]
+  return json_output
+
+
+def build_json_output_from_instances_dict(instances_dict, plural_name, 
output_conf_dir, output_path):
+  result = {}
+  for instance_name in instances_dict:
+    result[instance_name] = 
instances_dict[instance_name].build_json_output(output_conf_dir, output_path)
+
+  return {plural_name: result}
+
+
+# FIXME use mpack.json to determine category
+def find_module_category(path, module_name):
+  walk = os.walk(os.path.join(path, module_name))
+  if CONFIGS_DIRECTORY_NAME in next(walk)[1]:
+    return "CLIENT"
+  return "SERVER"
+
+
+def build_json_output(instances, output_conf_dir=False, output_path=False):
+  result = {}
+  for mpack_name in instances.keys():
+    result[mpack_name] = 
build_json_output_from_instances_dict(instances[mpack_name], 
MpackInstance.plural_name,
+                                                               
output_conf_dir, output_path)
+  return {'mpacks': result}
+
+
+class MetaMpack:
+  def __init__(self, name, version, component_module_map, mpack_json):
+    self.name = name
+    self.version = version
+    self.component_module_map = component_module_map
+    self.mpack_json = mpack_json
+    self.module_categoty_map = self.parse_mpack_json_into_module_category_map()
+    self.module_component_types_map = 
self.parse_mpack_json_into_module_component_types_map()
+
+  def parse_mpack_json_into_module_category_map(self):
+    result = {}
+    if not self.mpack_json:
+      return None
+    for module in self.mpack_json['modules']:
+      result[module['id']] = module['category']
+
+    return result
+
+  def parse_mpack_json_into_module_component_types_map(self):
+    result = {}
+    if not self.mpack_json:
+      return None
+    for module in self.mpack_json['modules']:
+      result[module['id']] = []
+      for component in module['components']:
+        result[module['id']].append(component['id'])
+
+    return result
+
+  def get_component_category(self, component_type):
+    for module in self.module_component_types_map:
+      if component_type in self.module_component_types_map[module]:
+        return self.module_categoty_map[module]
+    return None
+
+  @staticmethod
+  def parse_mpack(path, name, version):
+    # build components map from soft links
+    component_module_map = {}
+    for filename in os.listdir(path):
+      if os.path.islink(os.path.join(path, filename)):
+        component_module_map[filename] = os.path.realpath(os.path.join(path, 
filename))
+
+    return MetaMpack(name=name,
+                     version=version,
+                     component_module_map=component_module_map,
+                     mpack_json=json.load(open(os.path.join(path, 
MPACK_JSON_FILE_NAME))))
+
+  @staticmethod
+  def parse_mpacks(path):
+    result = {}
+    walk = os.walk(path)
+    for mpack_name in next(walk)[1]:
+      result[mpack_name] = 
MetaMpack.parse_into_mpack_objects(os.path.join(path, mpack_name))
+    return result
+
+  @staticmethod
+  def parse_into_mpack_objects(path):
+    result = {}
+    walk = os.walk(path)
+    for mpack_version in next(walk)[1]:
+      result[mpack_version] = MetaMpack.parse_mpack(path=os.path.join(path, 
mpack_version),
+                                                    
name=os.path.basename(path),
+                                                    version=mpack_version)
+    return result
+
+
+class Instance:
+  def build_json_output(self, output_conf_dir, output_path):
+    raise NotImplementedError("Should have implemented this")
+
+
+class MpackInstance(Instance):
+  plural_name = "mpack-instances"
+
+  def __init__(self, mpack_name, instance_name, groups_dict):
+    self.mpack_name = mpack_name
+    self.instance_name = instance_name
+    self.groups_dict = groups_dict
+
+  def build_json_output(self, output_conf_dir, output_path):
+    result = {}
+    for group in self.groups_dict.keys():
+      result[group] = 
build_json_output_from_instances_dict(self.groups_dict[group], 
ModuleInstance.plural_name,
+                                                            output_conf_dir, 
output_path)
+    return {"subgroups": result, 'name': self.instance_name}
+
+  def set_new_version(self, mpack_name, mpack_version):
+    for subgroup_name in self.groups_dict:
+      for module_name in self.groups_dict[subgroup_name]:
+        
self.groups_dict[subgroup_name][module_name].set_new_version(mpack_name, 
mpack_version)
+
+  @staticmethod
+  def parse_into_mpack_instance_dict(path, mpack_name, instance_name_filter, 
subgroup_name_filter,
+                                     module_name_filter, components_filter, 
components_name_filter_map):
+    result = {}
+    walk = os.walk(os.path.join(path, mpack_name))
+    for instance_name in next(walk)[1]:
+      if (
+            not instance_name_filter or instance_name_filter == instance_name) 
and instance_name != DEFAULT_MPACK_INSTANCE_NAME:
+        mpack_instance_object = 
MpackInstance.parse_into_mpack_instance_object(path, mpack_name,
+                                                                               
instance_name,
+                                                                               
subgroup_name_filter,
+                                                                               
module_name_filter,
+                                                                               
components_filter,
+                                                                               
components_name_filter_map)
+        if mpack_instance_object:
+          result[instance_name] = mpack_instance_object
+    return result
+
+  @staticmethod
+  def create_mpack_instance(mpack_name, mpack_version, mpack_instance, 
subgroup_name, module_name,
+                            components,
+                            components_map):
+    ModuleInstance.create_module_instance(mpack_name, mpack_version, 
mpack_instance, subgroup_name,
+                                          module_name, components, 
components_map)
+
+    default_mpack_instance_symlink = os.path.join(ROOT_FOLDER_PATH, 
INSTANCES_FOLDER_NAME, mpack_name,
+                                                  DEFAULT_MPACK_INSTANCE_NAME)
+    if not os.path.lexists(default_mpack_instance_symlink):
+      os.symlink(os.path.join(ROOT_FOLDER_PATH, INSTANCES_FOLDER_NAME, 
mpack_name, mpack_instance),
+                 default_mpack_instance_symlink)
+
+  @staticmethod
+  def parse_instances_with_filtering(path, mpack_name_filter=None, 
instance_name_filter=None, subgroup_name_filter=None,
+                                     module_name_filter=None, 
components_filter=None, components_name_filter_map=None):
+    result = {}
+    walk = os.walk(path)
+    for mpack_name in next(walk)[1]:
+      if not mpack_name_filter or mpack_name_filter == mpack_name:
+        mpack_instance_dict = 
MpackInstance.parse_into_mpack_instance_dict(path, mpack_name,
+                                                                           
instance_name_filter,
+                                                                           
subgroup_name_filter,
+                                                                           
module_name_filter,
+                                                                           
components_filter,
+                                                                           
components_name_filter_map)
+        if mpack_instance_dict:
+          result[mpack_name] = mpack_instance_dict
+    return result
+
+  @staticmethod
+  def parse_into_mpack_instance_object(root_path, mpack_name, instance_name, 
subgroup_name_filter=None,
+                                       module_name_filter=None, 
components_filter=None,
+                                       components_name_filter_map=None):
+    full_path = os.path.join(root_path, mpack_name, instance_name)
+
+    # return None if instance doesn't exist
+    if not os.path.exists(full_path):
+      return None
+
+    # build groups dictionary
+    groups_dict = {}
+    walk = os.walk(full_path)
+    for group_name in next(walk)[1]:
+      if not subgroup_name_filter or subgroup_name_filter == group_name:
+        module_instance_dict = ModuleInstance.parse_into_module_instance_dict(
+          os.path.join(full_path, group_name), module_name_filter, 
components_filter, components_name_filter_map)
+        if module_instance_dict:
+          groups_dict[group_name] = module_instance_dict
+
+    if not groups_dict:
+      return None
+    return MpackInstance(mpack_name, instance_name, groups_dict)
+
+
+class ModuleInstance(Instance):
+  plural_name = "modules"
+
+  def __init__(self, module_name, components_map, category):
+    self.module_name = module_name
+    self.components_map = components_map
+    self.category = category
+
+  @staticmethod
+  def parse_into_module_instance_dict(path, module_name_filter, 
components_filter, components_name_filter_map):
+    result = {}
+    walk = os.walk(path)
+    for module_name in next(walk)[1]:
+      if not module_name_filter or module_name_filter == module_name:
+
+        module_category = find_module_category(path, module_name)
+
+        if module_category == "CLIENT":
+          components_map = 
ComponentInstance(name=DEFAULT_COMPONENT_INSTANCE_NAME,
+                                             component_path=os.path.join(path, 
module_name),
+                                             path_exec=os.path.realpath(
+                                               os.path.join(path, module_name, 
CURRENT_SOFTLINK_NAME)), is_client=True)
+        else:
+          components_map = 
ComponentInstance.parse_into_components_dict(os.path.join(path, module_name),
+                                                                        
components_filter,
+                                                                        
components_name_filter_map)
+        if components_map:
+          result[module_name] = ModuleInstance(module_name, components_map, 
module_category)
+    return result
+
+  @staticmethod
+  def create_module_instance(mpack_name, mpack_version, mpack_instance, 
subgroup_name, module_name,
+                             components,
+                             components_map):
+    meta_mpack = MetaMpack.parse_mpack(
+      path=os.path.join(ROOT_FOLDER_PATH, MPACKS_FOLDER_NAME, mpack_name, 
mpack_version),
+      name=mpack_name,
+      version=mpack_version)
+
+    is_client_module = meta_mpack.module_categoty_map[module_name] == "CLIENT"
+    if components:
+      if components == '*':
+        components = meta_mpack.module_component_types_map[module_name]
+      for component_type in components:
+        ComponentInstance.create_component_instance(mpack_name, mpack_version, 
mpack_instance, subgroup_name,
+                                                    module_name, 
component_type, DEFAULT_COMPONENT_INSTANCE_NAME,
+                                                    is_client_module)
+    else:
+      for component_type in components_map:
+        for component_instance_name in components_map[component_type]:
+          ComponentInstance.create_component_instance(mpack_name, 
mpack_version, mpack_instance, subgroup_name,
+                                                      module_name, 
component_type, component_instance_name,
+                                                      is_client_module)
+
+  def set_new_version(self, mpack_name, mpack_version):
+    if self.category == 'CLIENT':
+      component_instance = self.components_map
+      print("\nSetting new version for component : " + 
component_instance.component_path)
+      component_instance.set_new_version(mpack_name, mpack_version, 
self.module_name)
+    else:
+      for component_type in self.components_map:
+        for component_name in self.components_map[component_type]:
+          component_instance = 
self.components_map[component_type][component_name]
+          print("\nSetting new version for component : " + 
component_instance.component_path)
+          component_instance.set_new_version(mpack_name, mpack_version, 
component_type)
+
+  def build_json_output(self, output_conf_dir, output_path):
+    result = {}
+    if self.category == 'CLIENT':
+      result['component_instances'] = {'default': 
self.components_map.build_json_output(output_conf_dir, output_path)}
+    else:
+      for component_type in self.components_map.keys():
+        result[component_type] = 
build_json_output_from_instances_dict(self.components_map[component_type],
+                                                                       
ComponentInstance.plural_name,
+                                                                       
output_conf_dir, output_path)
+      result = {'components': result}
+
+    result['category'] = self.category
+    result['name'] = self.module_name
+    return result
+
+
+class ComponentInstance(Instance):
+  plural_name = "component-instances"
+
+  def __init__(self, name, component_path, path_exec, is_client=False):
+    self.name = name
+    self.component_path = component_path
+    self.path_exec = path_exec
+    self.is_client = is_client
+
+  def set_new_version(self, mpack_name, mpack_version, component_type):
+    mpack_path = os.path.join(ROOT_FOLDER_PATH, MPACKS_FOLDER_NAME, 
mpack_name, mpack_version, component_type)
+    target_link = os.path.join(self.component_path, CURRENT_SOFTLINK_NAME)
+    if os.path.lexists(target_link):
+      os.remove(target_link)
+      print "\nRemoved old link " + target_link
+
+    os.symlink(mpack_path, target_link)
+    print "\nCreated new link " + target_link + " -> " + mpack_path
+
+  @staticmethod
+  def parse_into_component_instance_dict(path, component_names_filter=None):
+    result = {}
+    walk = os.walk(path)
+    for component_instance_name in next(walk)[1]:
+      if not component_names_filter or component_instance_name in 
component_names_filter:
+        result[component_instance_name] = 
ComponentInstance(name=component_instance_name,
+                                                            
component_path=os.path.join(path, component_instance_name),
+                                                            
path_exec=os.path.realpath(
+                                                              
os.path.join(path, component_instance_name,
+                                                                           
CURRENT_SOFTLINK_NAME)))
+    return result
+
+  @staticmethod
+  def parse_into_components_dict(path, components_filter, 
components_name_filter_map):
+    result = {}
+    walk = os.walk(path)
+    for component_type in next(walk)[1]:
+      if components_filter:
+        if components_filter == '*':
+          result[component_type] = 
ComponentInstance.parse_into_component_instance_dict(
+            os.path.join(path, component_type))
+        else:
+          component_instance_dict = 
ComponentInstance.parse_into_component_instance_dict(
+            os.path.join(path, component_type), components_filter)
+          if component_instance_dict:
+            result[component_type] = component_instance_dict
+      elif not components_name_filter_map:
+        result[component_type] = 
ComponentInstance.parse_into_component_instance_dict(
+          os.path.join(path, component_type))
+      elif component_type in components_name_filter_map.keys():
+        component_instance_dict = 
ComponentInstance.parse_into_component_instance_dict(
+          os.path.join(path, component_type), 
components_name_filter_map[component_type])
+        if component_instance_dict:
+          result[component_type] = component_instance_dict
+    return result
+
+  @staticmethod
+  def create_component_instance(mpack_name, mpack_version, mpack_instance, 
subgroup_name, module_name,
+                                component_type, component_instance_name, 
is_client_module):
+    if is_client_module:
+      component_path = os.path.join(ROOT_FOLDER_PATH, INSTANCES_FOLDER_NAME, 
mpack_name, mpack_instance, subgroup_name,
+                                    component_type)
+    else:
+      component_path = os.path.join(ROOT_FOLDER_PATH, INSTANCES_FOLDER_NAME, 
mpack_name, mpack_instance, subgroup_name,
+                                    module_name, component_type, 
component_instance_name)
+    mpack_path = os.path.join(ROOT_FOLDER_PATH, MPACKS_FOLDER_NAME, 
mpack_name, mpack_version, component_type)
+
+    if not os.path.lexists(mpack_path):
+      raise ValueError("Path doesn't exist: " + mpack_path)
+
+    os.makedirs(component_path)
+
+    os.symlink(mpack_path, os.path.join(component_path, CURRENT_SOFTLINK_NAME))
+
+    os.makedirs(os.path.join(component_path, CONFIGS_DIRECTORY_NAME))
+    print "\n Created " + component_path
+
+  def build_json_output(self, output_conf_dir, output_path):
+    result = {'name': self.name}
+    if output_conf_dir:
+      result['config_dir'] = os.path.join(self.component_path, 
CONFIGS_DIRECTORY_NAME)
+    if output_path:
+      result['path'] = self.path_exec
+    return result
diff --git 
a/mpack-instance-manager/src/main/python/instance_manager/mpack-instance-manager.py
 
b/mpack-instance-manager/src/main/python/instance_manager/mpack-instance-manager.py
new file mode 100644
index 0000000..81c180d
--- /dev/null
+++ 
b/mpack-instance-manager/src/main/python/instance_manager/mpack-instance-manager.py
@@ -0,0 +1,138 @@
+#!/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.
+
+"""
+from instance_manager import *
+
+import optparse
+import sys
+import ast
+
+CREATE_MPACK_INSTANCE_ACTION = 'create-mpack-instance'
+SET_MPACK_INSTANCE_ACTION = 'set-mpack-instance'
+GET_CONF_DIR_ACTION = 'get-conf-dir'
+LIST_INSTANCES_ACTION = 'list-instances'
+
+
+def init_action_parser(action, parser):
+  action_parser_map = {
+    CREATE_MPACK_INSTANCE_ACTION: init_create_parser_options,
+    SET_MPACK_INSTANCE_ACTION: init_set_parser_options,
+    GET_CONF_DIR_ACTION: init_get_parser_options,
+    LIST_INSTANCES_ACTION: init_get_parser_options
+  }
+  try:
+    action_parser_map[action](parser)
+  except KeyError:
+    parser.error("Invalid action: " + action)
+
+
+def init_create_parser_options(parser):
+  parser.add_option('--mpack', default=None, help="selected 'mpack_name'. eg: 
edw, core", dest="mpack")
+  parser.add_option('--mpack-version', default=None, help="selected 
'mpack_version'. eg. 1.0.0.-b1",
+                    dest="mpack_version")
+  parser.add_option('--mpack-instance', default=None,
+                    help="new/existing 'mpack_instance_name'. eg: Production, 
eCommerce", dest="mpack_instance")
+  parser.add_option('--subgroup-name', default="default", help="new/existing 
'subgroup_name' eg: hive-for-finance",
+                    dest="subgroup_name")
+  parser.add_option('--module-name', default=None,
+                    help="selected 'service/client_module' eg: hive, hdfs, 
hive_client etc", dest="module_name")
+  parser.add_option('--components', default=None,
+                    help="list of 'components_instances_name' to be created. 
(default) OR '*' for all components",
+                    dest="components")
+  parser.add_option('--components-map', default=None,
+                    help="map of 'component type' (eg: hive_server, metastore 
etc) as key and List of component instance name(s) to be given (eg: HS-1, 
finance_metastore) as value OR Empty map to create single instance of all 
components with name 'default'",
+                    dest="components_map")
+
+
+def init_set_parser_options(parser):
+  parser.add_option('--mpack', default=None, help="selected 'mpack_name'. eg: 
edw, core", dest="mpack")
+  parser.add_option('--mpack-version', default=None,
+                    help="selected 'mpack_version' on which we want to move 
to. eg. 1.5.0.-b1", dest="mpack_version")
+  parser.add_option('--mpack-instance', default=None, help="existing 
'mpack_instance_name'. eg: Production, eCommerce",
+                    dest="mpack_instance")
+  parser.add_option('--subgroup-name', default="default", help="existing 
'subgroup_name' eg: hive-for-finance",
+                    dest="subgroup_name")
+  parser.add_option('--module-name', default=None,
+                    help="selected 'service/client_module' eg: hive, hdfs, 
hive_client etc", dest="module_name")
+  parser.add_option('--components', default=None,
+                    help="list of 'components_instances_name' to be updated. 
(default) OR '*' for all components",
+                    dest="components")
+  parser.add_option('--components-map', default=None,
+                    help="map of 'component type' (eg: hive_server, metastore 
etc) as key and List of component instance name(s) to be given (eg: HS-1, 
finance_metastore) as value OR Empty map to update instance of all components 
with name 'default'",
+                    dest="components_map")
+
+
+def init_get_parser_options(parser):
+  parser.add_option('--mpack', default=None,
+                    help="'mpack_name' to which component instance belongs. 
eg: edw, core'. eg: edw, core",
+                    dest="mpack")
+  parser.add_option('--mpack-instance', default=None, 
help="'mpack_instance_name'. (eg: default)",
+                    dest="mpack_instance")
+  parser.add_option('--subgroup-name', default="default", 
help="'subgroup_name' eg: hive-for-finance",
+                    dest="subgroup_name")
+  parser.add_option('--module-name', default=None,
+                    help="selected 'service/client_module' eg: hive, hdfs, 
hive_client etc", dest="module_name")
+  parser.add_option('--components-map', default=None,
+                    help="map of 'component type' (eg: hive_server, metastore 
etc) as key and List of component instance name(s) to be given (eg: HS-1, 
finance_metastore) as value OR Empty map for all component instances present",
+                    dest="components_map")
+
+
+def main(options, args):
+  action = sys.argv[1]
+  if action == CREATE_MPACK_INSTANCE_ACTION:
+    create_mpack(mpack_name=options.mpack, mpack_version=options.mpack_version,
+                 mpack_instance=options.mpack_instance,
+                 subgroup_name=options.subgroup_name, 
module_name=options.module_name,
+                 components=options.components,
+                 components_map=ast.literal_eval(options.components_map))
+
+  elif action == SET_MPACK_INSTANCE_ACTION:
+    set_mpack_instance(mpack=options.mpack, 
mpack_version=options.mpack_version,
+                       mpack_instance=options.mpack_instance,
+                       subgroup_name=options.subgroup_name, 
module_name=options.module_name,
+                       components=options.components,
+                       components_map=ast.literal_eval(options.components_map))
+
+  elif action == GET_CONF_DIR_ACTION:
+    print get_conf_dir(mpack=options.mpack, 
mpack_instance=options.mpack_instance,
+                       subgroup_name=options.subgroup_name, 
module_name=options.module_name,
+                       components_map=ast.literal_eval(options.components_map))
+
+  elif action == LIST_INSTANCES_ACTION:
+    print list_instances(mpack=options.mpack, 
mpack_instance=options.mpack_instance,
+                         subgroup_name=options.subgroup_name, 
module_name=options.module_name,
+                         
components_map=ast.literal_eval(options.components_map))
+
+
+if __name__ == "__main__":
+  if len(sys.argv) < 2:
+    print(
+      "Missing the command. Possible options are: 
{create-mpack-instance|set-mpack-instance|get-conf-dir|list-instances}")
+    sys.exit(1)
+
+  parser = optparse.OptionParser()
+  action = sys.argv[1]
+  init_action_parser(action, parser)
+  (options, args) = parser.parse_args()
+
+  try:
+    main(options, args)
+  except (KeyboardInterrupt, EOFError):
+    print("\nAborting ... Keyboard Interrupt.")
+    sys.exit(1)
diff --git a/mpack-instance-manager/src/packages/tarball/all.xml 
b/mpack-instance-manager/src/packages/tarball/all.xml
new file mode 100644
index 0000000..1c90f28
--- /dev/null
+++ b/mpack-instance-manager/src/packages/tarball/all.xml
@@ -0,0 +1,37 @@
+<?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
+  -->
+  <formats>
+    <format>dir</format>
+    <format>tar.gz</format>
+  </formats>
+  <includeBaseDirectory>false</includeBaseDirectory>
+  <fileSets>
+    <fileSet>
+      <directoryMode>755</directoryMode>
+      <fileMode>755</fileMode>
+      <directory>src/main/python/instance_manager</directory>
+      <outputDirectory>${instanceManagerInstallDir}</outputDirectory>
+    </fileSet>
+  </fileSets>
+</assembly>
diff --git 
a/mpack-instance-manager/src/test/python/instance_manager/test_instance_manager.py
 
b/mpack-instance-manager/src/test/python/instance_manager/test_instance_manager.py
new file mode 100644
index 0000000..88870e3
--- /dev/null
+++ 
b/mpack-instance-manager/src/test/python/instance_manager/test_instance_manager.py
@@ -0,0 +1,265 @@
+#!/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.
+
+"""
+from unittest import TestCase
+
+import instance_manager
+import os
+import shutil
+import json
+
+TMP_ROOT_FOLDER = "/tmp/instance_manager_test"
+# set root directory to tmp location
+instance_manager.ROOT_FOLDER_PATH = TMP_ROOT_FOLDER
+
+MPACK_NAME = 'hdpcore'
+MPACK_VERSION_1 = '1.0.0-b1'
+MPACK_VERSION_2 = '1.5.0-b1'
+INSTANCE_NAME_1 = 'Production'
+SUBGROUP_NAME = 'default'
+CLIENT_MODULE_NAME = 'hdfs-clients'
+CLIENT_COMPONENT_NAME = 'hdfs_client'
+SERVER_MODULE_NAME = 'hdfs'
+SERVER_COMPONENT_NAME = 'hdfs_server'
+MODULE_VERSION_MAPPING = {CLIENT_MODULE_NAME: '3.1.0.0-b1', 
SERVER_MODULE_NAME: '3.1.0.0-b1'}
+MODULE_COMPONENT_MAPPING = {CLIENT_MODULE_NAME: CLIENT_COMPONENT_NAME, 
SERVER_MODULE_NAME: SERVER_COMPONENT_NAME}
+
+MPACK_JSON = {"modules": [
+  {"category": "CLIENT", "components": [{"id": CLIENT_COMPONENT_NAME}], "id": 
CLIENT_MODULE_NAME},
+  {"category": "SERVER", "components": [{"id": SERVER_COMPONENT_NAME}], "id": 
SERVER_MODULE_NAME}]}
+
+
+class TestInstanceManager(TestCase):
+  def setUp(self):
+    build_rpm_structure()
+
+  def tearDown(self):
+    remove_rpm_structure()
+
+  def test_create_mpack_client_module(self):
+    create_mpack_with_defaults(module_name=CLIENT_MODULE_NAME)
+    current_link = os.path.join(TMP_ROOT_FOLDER, 
instance_manager.INSTANCES_FOLDER_NAME, MPACK_NAME,
+                                INSTANCE_NAME_1, SUBGROUP_NAME, 
CLIENT_COMPONENT_NAME,
+                                instance_manager.CURRENT_SOFTLINK_NAME)
+
+    self.assertTrue(os.path.exists(current_link))
+    self.assertEquals(os.readlink(current_link),
+                      os.path.join(TMP_ROOT_FOLDER, 
instance_manager.MPACKS_FOLDER_NAME, MPACK_NAME,
+                                   MPACK_VERSION_1, CLIENT_COMPONENT_NAME))
+
+    self.assertTrue(os.path.exists(os.path.join(TMP_ROOT_FOLDER, 
instance_manager.INSTANCES_FOLDER_NAME, MPACK_NAME,
+                                                
instance_manager.DEFAULT_MPACK_INSTANCE_NAME)))
+
+  def test_create_mpack_server_module_with_default_component_instance(self):
+    create_mpack_with_defaults()
+    current_link = os.path.join(TMP_ROOT_FOLDER, 
instance_manager.INSTANCES_FOLDER_NAME, MPACK_NAME,
+                                INSTANCE_NAME_1, SUBGROUP_NAME, 
SERVER_MODULE_NAME, SERVER_COMPONENT_NAME,
+                                
instance_manager.DEFAULT_COMPONENT_INSTANCE_NAME,
+                                instance_manager.CURRENT_SOFTLINK_NAME)
+
+    self.assertTrue(os.path.exists(current_link))
+    self.assertEquals(os.readlink(current_link),
+                      os.path.join(TMP_ROOT_FOLDER, 
instance_manager.MPACKS_FOLDER_NAME, MPACK_NAME,
+                                   MPACK_VERSION_1, SERVER_COMPONENT_NAME))
+
+    self.assertTrue(os.path.exists(os.path.join(TMP_ROOT_FOLDER, 
instance_manager.INSTANCES_FOLDER_NAME, MPACK_NAME,
+                                                
instance_manager.DEFAULT_MPACK_INSTANCE_NAME)))
+
+  def test_create_mpack_server_module_with_multiple_component_instances(self):
+    create_mpack_with_defaults(components=None, 
components_map={SERVER_COMPONENT_NAME: ['server1', 'server2']})
+
+    current_link_1 = os.path.join(TMP_ROOT_FOLDER, 
instance_manager.INSTANCES_FOLDER_NAME, MPACK_NAME,
+                                  INSTANCE_NAME_1, SUBGROUP_NAME, 
SERVER_MODULE_NAME, SERVER_COMPONENT_NAME,
+                                  'server1', 
instance_manager.CURRENT_SOFTLINK_NAME)
+    self.assertTrue(os.path.exists(current_link_1))
+    self.assertEqual(os.readlink(current_link_1),
+                     os.path.join(TMP_ROOT_FOLDER, 
instance_manager.MPACKS_FOLDER_NAME, MPACK_NAME,
+                                  MPACK_VERSION_1, SERVER_COMPONENT_NAME))
+
+    current_link_2 = os.path.join(TMP_ROOT_FOLDER, 
instance_manager.INSTANCES_FOLDER_NAME, MPACK_NAME,
+                                  INSTANCE_NAME_1, SUBGROUP_NAME, 
SERVER_MODULE_NAME, SERVER_COMPONENT_NAME,
+                                  'server2', 
instance_manager.CURRENT_SOFTLINK_NAME)
+
+    self.assertTrue(os.path.exists(current_link_2))
+    self.assertEqual(os.readlink(current_link_2),
+                     os.path.join(TMP_ROOT_FOLDER, 
instance_manager.MPACKS_FOLDER_NAME, MPACK_NAME,
+                                  MPACK_VERSION_1, SERVER_COMPONENT_NAME))
+
+  def test_set_version_asterisk(self):
+    create_mpack_with_defaults()
+
+    instance_manager.set_mpack_instance(MPACK_NAME, MPACK_VERSION_2, 
INSTANCE_NAME_1, SUBGROUP_NAME,
+                                        SERVER_MODULE_NAME, '*')
+
+    current_link = os.path.join(TMP_ROOT_FOLDER, 
instance_manager.INSTANCES_FOLDER_NAME, MPACK_NAME,
+                                INSTANCE_NAME_1, SUBGROUP_NAME, 
SERVER_MODULE_NAME, SERVER_COMPONENT_NAME,
+                                
instance_manager.DEFAULT_COMPONENT_INSTANCE_NAME,
+                                instance_manager.CURRENT_SOFTLINK_NAME)
+
+    self.assertEqual(os.readlink(current_link),
+                     os.path.join(TMP_ROOT_FOLDER, 
instance_manager.MPACKS_FOLDER_NAME, MPACK_NAME,
+                                  MPACK_VERSION_2, SERVER_COMPONENT_NAME))
+
+  def test_set_version_for_one_of_two_component_instances(self):
+    create_mpack_with_defaults(components=None, 
components_map={SERVER_COMPONENT_NAME: ['server1', 'server2']})
+
+    instance_manager.set_mpack_instance(MPACK_NAME, MPACK_VERSION_2, 
INSTANCE_NAME_1, SUBGROUP_NAME,
+                                        SERVER_MODULE_NAME, None, 
{SERVER_COMPONENT_NAME: ['server2']})
+
+    current_link_1 = os.path.join(TMP_ROOT_FOLDER, 
instance_manager.INSTANCES_FOLDER_NAME, MPACK_NAME,
+                                  INSTANCE_NAME_1, SUBGROUP_NAME, 
SERVER_MODULE_NAME, SERVER_COMPONENT_NAME,
+                                  'server1', 
instance_manager.CURRENT_SOFTLINK_NAME)
+    self.assertEqual(os.readlink(current_link_1),
+                     os.path.join(TMP_ROOT_FOLDER, 
instance_manager.MPACKS_FOLDER_NAME, MPACK_NAME,
+                                  MPACK_VERSION_1, SERVER_COMPONENT_NAME))
+
+    current_link_2 = os.path.join(TMP_ROOT_FOLDER, 
instance_manager.INSTANCES_FOLDER_NAME, MPACK_NAME,
+                                  INSTANCE_NAME_1, SUBGROUP_NAME, 
SERVER_MODULE_NAME, SERVER_COMPONENT_NAME,
+                                  'server2', 
instance_manager.CURRENT_SOFTLINK_NAME)
+
+    self.assertEqual(os.readlink(current_link_2),
+                     os.path.join(TMP_ROOT_FOLDER, 
instance_manager.MPACKS_FOLDER_NAME, MPACK_NAME,
+                                  MPACK_VERSION_2, SERVER_COMPONENT_NAME))
+
+  def test_get_conf_dir_all(self):
+    create_mpack_with_defaults(module_name=CLIENT_MODULE_NAME)
+    create_mpack_with_defaults(module_name=SERVER_MODULE_NAME, components=None,
+                               components_map={SERVER_COMPONENT_NAME: 
['server1']})
+
+    conf_dir_json = instance_manager.get_conf_dir()
+
+    expected_json = {
+      "mpacks": {
+        "hdpcore": {
+          "mpack-instances": {
+            "Production": {
+              "name": "Production",
+              "subgroups": {
+                "default": {
+                  "modules": {
+                    "hdfs": {
+                      "category": "SERVER",
+                      "name": "hdfs",
+                      "components": {
+                        "hdfs_server": {
+                          "component-instances": {
+                            "server1": {
+                              "config_dir": 
"/tmp/instance_manager_test/instances/hdpcore/Production/default/hdfs/hdfs_server/server1/conf",
+                              "name": "server1"
+                            }
+                          }
+                        }
+                      }
+                    },
+                    "hdfs_client": {
+                      "category": "CLIENT",
+                      "component_instances": {
+                        "default": {
+                          "config_dir": 
"/tmp/instance_manager_test/instances/hdpcore/Production/default/hdfs_client/conf",
+                          "name": "default"
+                        }
+                      },
+                      "name": "hdfs_client"
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+    self.assertEqual(conf_dir_json, expected_json)
+
+  def test_list_instances_all(self):
+    create_mpack_with_defaults(module_name=CLIENT_MODULE_NAME)
+    create_mpack_with_defaults(module_name=SERVER_MODULE_NAME, components=None,
+                               components_map={SERVER_COMPONENT_NAME: 
['server1']})
+
+    conf_dir_json = instance_manager.list_instances()
+
+    expected_json = {
+      "mpacks": {
+        "hdpcore": {
+          "mpack-instances": {
+            "Production": {
+              "name": "Production",
+              "subgroups": {
+                "default": {
+                  "modules": {
+                    "hdfs": {
+                      "category": "SERVER",
+                      "name": "hdfs",
+                      "components": {
+                        "hdfs_server": {
+                          "component-instances": {
+                            "server1": {
+                              "path": 
"/tmp/instance_manager_test/modules/hdfs/3.1.0.0-b1",
+                              "name": "server1"
+                            }
+                          }
+                        }
+                      }
+                    },
+                    "hdfs_client": {
+                      "category": "CLIENT",
+                      "component_instances": {
+                        "default": {
+                          "path": 
"/tmp/instance_manager_test/modules/hdfs-clients/3.1.0.0-b1",
+                          "name": "default"
+                        }
+                      },
+                      "name": "hdfs_client"
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+    self.assertEqual(conf_dir_json, expected_json)
+
+
+def create_mpack_with_defaults(mpack_name=MPACK_NAME, 
mpack_version=MPACK_VERSION_1, mpack_instance=INSTANCE_NAME_1,
+                               subgroup_name=SUBGROUP_NAME, 
module_name=SERVER_MODULE_NAME, components='*',
+                               components_map=None):
+  instance_manager.create_mpack(mpack_name, mpack_version, mpack_instance,
+                                subgroup_name, module_name, components, 
components_map)
+
+
+def build_rpm_structure():
+  remove_rpm_structure()
+
+  mpack_path = os.path.join(TMP_ROOT_FOLDER, 
instance_manager.MPACKS_FOLDER_NAME, MPACK_NAME, MPACK_VERSION_1)
+  os.makedirs(mpack_path)
+  with open(os.path.join(mpack_path, "mpack.json"), "w") as mpack_json:
+    json.dump(MPACK_JSON, mpack_json)
+
+  modules_path = os.path.join(TMP_ROOT_FOLDER, 
instance_manager.MODULES_FOLDER_NAME)
+  for module_name in MODULE_VERSION_MAPPING:
+    os.makedirs(os.path.join(modules_path, module_name, 
MODULE_VERSION_MAPPING[module_name], 'bin'))
+    os.symlink(os.path.join(modules_path, module_name, 
MODULE_VERSION_MAPPING[module_name]),
+               os.path.join(mpack_path, MODULE_COMPONENT_MAPPING[module_name]))
+
+
+def remove_rpm_structure():
+  if os.path.exists(TMP_ROOT_FOLDER):
+    shutil.rmtree(TMP_ROOT_FOLDER)
diff --git a/mpack-instance-manager/src/test/python/unitTests.py 
b/mpack-instance-manager/src/test/python/unitTests.py
new file mode 100644
index 0000000..b8ace64
--- /dev/null
+++ b/mpack-instance-manager/src/test/python/unitTests.py
@@ -0,0 +1,129 @@
+#!/usr/bin/env python
+
+'''
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+'''
+
+import unittest
+import os
+import sys
+from random import shuffle
+import fnmatch
+
+TEST_MASK = '[Tt]est*.py'
+CUSTOM_TEST_MASK = '_[Tt]est*.py'
+
+
+def get_parent_path(base, directory_name):
+  """
+  Returns absolute path for directory_name, if directory_name present in base.
+  For example, base=/home/user/test2, directory_name=user - will return 
/home/user
+  """
+  done = False
+  while not done:
+    base = os.path.dirname(base)
+    if base == "/":
+      return None
+    if os.path.split(base)[-1] == directory_name:
+      done = True
+    else:
+      done = False
+  return base
+
+
+def get_test_files(path, mask=None, recursive=True):
+  """
+  Returns test files for path recursively
+  """
+  current = []
+  directory_items = os.listdir(path)
+  directory_items.sort()
+
+  for item in directory_items:
+    add_to_pythonpath = False
+    item_path = os.path.join(path, item)
+    if os.path.isfile(item_path):
+      if fnmatch.fnmatch(item, mask):
+        add_to_pythonpath = True
+        current.append(item)
+    elif os.path.isdir(item_path):
+      if recursive:
+        current.extend(get_test_files(item_path, mask=mask))
+    if add_to_pythonpath:
+      sys.path.append(path)
+  return current
+
+
+def main():
+  custom_tests = False
+  if len(sys.argv) > 1:
+    if sys.argv[1] == "true":
+      custom_tests = True
+  pwd = os.path.abspath(os.path.dirname(__file__))
+
+  project_folder = get_parent_path(pwd, 'mpack-instance-manager')
+  sys.path.append(project_folder + "/src/test/python")
+  sys.path.append(project_folder + "/src/main/python")
+  sys.path.append(project_folder + "/src/main/python/instance_manager")
+
+  has_failures = False
+  test_runs = 0
+  test_failures = []
+  test_errors = []
+  # run mpack-instance-manager tests
+  sys.stderr.write("Running tests\n")
+  if custom_tests:
+    test_mask = CUSTOM_TEST_MASK
+  else:
+    test_mask = TEST_MASK
+
+  tests = get_test_files(pwd, mask=test_mask, recursive=True)
+  shuffle(tests)
+  modules = [os.path.basename(s)[:-3] for s in tests]
+  suites = [unittest.defaultTestLoader.loadTestsFromName(name) for name in
+            modules]
+  testSuite = unittest.TestSuite(suites)
+  textRunner = unittest.TextTestRunner(verbosity=2).run(testSuite)
+  test_runs += textRunner.testsRun
+  test_errors.extend([(str(item[0]), str(item[1]), "ERROR") for item in 
textRunner.errors])
+  test_failures.extend([(str(item[0]), str(item[1]), "FAIL") for item in 
textRunner.failures])
+  tests_status = textRunner.wasSuccessful() and not has_failures
+
+  if not tests_status:
+    
sys.stderr.write("----------------------------------------------------------------------\n")
+    sys.stderr.write("Failed tests:\n")
+  for failed_tests in [test_errors, test_failures]:
+    for err in failed_tests:
+      sys.stderr.write("{0}: {1}\n".format(err[2], err[0]))
+      
sys.stderr.write("----------------------------------------------------------------------\n")
+      sys.stderr.write("{0}\n".format(err[1]))
+  
sys.stderr.write("----------------------------------------------------------------------\n")
+  sys.stderr.write("Total run:{0}\n".format(test_runs))
+  sys.stderr.write("Total errors:{0}\n".format(len(test_errors)))
+  sys.stderr.write("Total failures:{0}\n".format(len(test_failures)))
+
+  if tests_status:
+    sys.stderr.write("OK\n")
+    exit_code = 0
+  else:
+    sys.stderr.write("ERROR\n")
+    exit_code = 1
+  return exit_code
+
+
+if __name__ == "__main__":
+  sys.exit(main())
diff --git a/pom.xml b/pom.xml
index 36df69a..a427040 100644
--- a/pom.xml
+++ b/pom.xml
@@ -471,6 +471,7 @@
         <module>ambari-server</module>
         <module>ambari-funtest</module>
         <module>ambari-agent</module>
+        <module>mpack-instance-manager</module>
         <module>ambari-client</module>
         <module>ambari-shell</module>
         <module>ambari-logsearch</module>
@@ -495,6 +496,7 @@
         <module>ambari-server</module>
         <module>ambari-funtest</module>
         <module>ambari-agent</module>
+        <module>mpack-instance-manager</module>
         <module>ambari-client</module>
         <module>ambari-shell</module>
       </modules>
@@ -509,6 +511,7 @@
         <module>ambari-server</module>
         <module>ambari-funtest</module>
         <module>ambari-agent</module>
+        <module>mpack-instance-manager</module>
         <module>ambari-client</module>
         <module>ambari-shell</module>
         <module>ambari-logsearch</module>
@@ -532,6 +535,7 @@
         <module>ambari-server</module>
         <module>ambari-funtest</module>
         <module>ambari-agent</module>
+        <module>mpack-instance-manager</module>
         <module>ambari-client</module>
         <module>ambari-shell</module>
         <module>ambari-logsearch</module>

-- 
To stop receiving notification emails like this one, please contact
d...@apache.org.

Reply via email to