AMBARI-14939. [Ambari tarballs] optionally install required packages (aonishuk)


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

Branch: refs/heads/branch-dev-patch-upgrade
Commit: ed492292cd4fedd41ebe95ba97a73e57cceb0bae
Parents: 6919586
Author: Andrew Onishuk <aonis...@hortonworks.com>
Authored: Fri Feb 5 15:44:04 2016 +0200
Committer: Andrew Onishuk <aonis...@hortonworks.com>
Committed: Fri Feb 5 15:44:04 2016 +0200

----------------------------------------------------------------------
 ambari-agent/pom.xml                            |  38 ++++--
 .../src/main/package/dependencies.properties    |  32 +++++
 .../src/main/repo/install_ambari_tarball.py     | 117 ++++++++++++++++++-
 ambari-server/pom.xml                           |  40 +++++--
 .../src/main/package/dependencies.properties    |  33 ++++++
 5 files changed, 239 insertions(+), 21 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/ed492292/ambari-agent/pom.xml
----------------------------------------------------------------------
diff --git a/ambari-agent/pom.xml b/ambari-agent/pom.xml
index d049a6c..c2c993f 100644
--- a/ambari-agent/pom.xml
+++ b/ambari-agent/pom.xml
@@ -43,10 +43,7 @@
     
<jinja.install.dir>/usr/lib/ambari-agent/lib/ambari_jinja2</jinja.install.dir>
     
<simplejson.install.dir>/usr/lib/ambari-agent/lib/ambari_simplejson</simplejson.install.dir>
     <lib.dir>/usr/lib/ambari-agent/lib</lib.dir>
-    <python.ver>python &gt;= 2.6</python.ver>
-    <deb.python.ver>python (&gt;= 2.6)</deb.python.ver>
     <deb.architecture>amd64</deb.architecture>
-    <deb.dependency.list>openssl, zlibc, 
${deb.python.ver}</deb.dependency.list>
     <ambari.server.module>../ambari-server</ambari.server.module>
     <target.cache.dir>${project.build.directory}/cache/</target.cache.dir>
     
<resource.keeper.script>${ambari.server.module}/src/main/python/ambari_server/resourceFilesKeeper.py</resource.keeper.script>
@@ -140,6 +137,23 @@
       </plugin>
       <plugin>
         <groupId>org.codehaus.mojo</groupId>
+        <artifactId>properties-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <phase>package</phase>
+            <goals>
+              <goal>read-project-properties</goal>
+            </goals>
+            <configuration>
+              <files>
+                
<file>${basedir}/src/main/package/dependencies.properties</file>
+              </files>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
         <artifactId>rpm-maven-plugin</artifactId>
         <version>2.1.4</version>
         <executions>
@@ -156,10 +170,7 @@
           <group>Development</group>
           <description>Maven Recipe: RPM Package.</description>
           <requires>
-            <require>openssl</require>
-            <require>rpm-python</require>
-            <require>zlib</require>
-            <require>${python.ver}</require>
+            <require>${rpm.dependency.list}</require>
           </requires>
           <postinstallScriptlet>
             <scriptFile>src/main/package/rpm/postinstall.sh</scriptFile>
@@ -355,6 +366,19 @@
                 <resource>
                   
<directory>${basedir}/src/main/package/deb/control</directory>
                 </resource>
+                <resource>
+                  <directory>${basedir}/src/main/package</directory>
+                  <includes>
+                    <include>dependencies.properties</include>
+                  </includes>
+                </resource>
+                <resource>
+                  
<directory>${project.basedir}/../ambari-common/src/main/python/ambari_commons</directory>
+                  <includes>
+                    <include>os_check.py</include>
+                    <include>resources/os_family.json</include>
+                  </includes>
+                </resource>
               </resources>
             </configuration>
           </execution>

http://git-wip-us.apache.org/repos/asf/ambari/blob/ed492292/ambari-agent/src/main/package/dependencies.properties
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/package/dependencies.properties 
b/ambari-agent/src/main/package/dependencies.properties
new file mode 100644
index 0000000..07b0b68
--- /dev/null
+++ b/ambari-agent/src/main/package/dependencies.properties
@@ -0,0 +1,32 @@
+# 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 rega4rding 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.
+
+# Please make sure the format of the file is one of the following
+# rpm.dependency.list=...
+# rpm.dependency.list.[os_family_name]=...
+# rpm.dependency.list.[os_family_name][starting_from_version]=...
+# deb.dependency.list=...
+# deb.dependency.list.[os_family_name]=...
+# deb.dependency.list.[os_family_name][starting_from_version]=...
+# 
+# Examples:
+# rpm.dependency.list.suse=openssl,\nRequires: rpm-python # for all suse 
family os
+# rpm.dependency.list.suse11=curl # for all suse family os higher or equal to 
11.
+#
+# Such a format is respected by install_ambari_tarball.py by default, 
+# however should be encouraged manually in pom.xml.
+
+rpm.dependency.list=openssl,\nRequires: rpm-python,\nRequires: 
zlib,\nRequires: python >= 2.6
+deb.dependency.list=openssl, zlibc, python (>= 2.6)
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/ed492292/ambari-common/src/main/repo/install_ambari_tarball.py
----------------------------------------------------------------------
diff --git a/ambari-common/src/main/repo/install_ambari_tarball.py 
b/ambari-common/src/main/repo/install_ambari_tarball.py
index aa33ede..5c65b60 100644
--- a/ambari-common/src/main/repo/install_ambari_tarball.py
+++ b/ambari-common/src/main/repo/install_ambari_tarball.py
@@ -17,11 +17,13 @@ See the License for the specific language governing 
permissions and
 limitations under the License.
 '''
 
+import re
 import os
 import sys
 import logging
 import subprocess
 from optparse import OptionParser
+import ConfigParser
 
 USAGE = "Usage: %prog [OPTION]... URL"
 DESCRIPTION = "URL should point to full tar.gz location e.g.: 
https://public-repo-1.hortonworks.com/something/ambari-server.tar.gz";
@@ -32,9 +34,16 @@ PREINST_SCRIPT = "preinst"
 PRERM_SCRIPT = "prerm"
 POSTINST_SCRIPT = "postinst"
 POSTRM_SCRIPT = "postrm"
+OS_CHECK = "os_check.py"
+OS_PACKAGE_DEPENDENCIES = "dependencies.properties"
+OS_FAMILY_DESCRIPTION = "resources/os_family.json"
+RPM_DEPENDENCIES_PROPERTY =  "rpm.dependency.list"
+DEB_DEPENDENCIES_PROPERTY =  "deb.dependency.list"
 
-ROOT_FOLDER_ENV_VARIABLE = "AMBARI_ROOT_FOLDER"
+FILES_TO_DOWNLOAD = [PREINST_SCRIPT, PRERM_SCRIPT, POSTINST_SCRIPT, 
POSTRM_SCRIPT, OS_CHECK, OS_FAMILY_DESCRIPTION, OS_PACKAGE_DEPENDENCIES]
 
+ROOT_FOLDER_ENV_VARIABLE = "AMBARI_ROOT_FOLDER"
+          
 class Utils:
   verbose = False
   @staticmethod
@@ -65,26 +74,72 @@ class Utils:
       
     return out
   
+  @staticmethod
+  def install_package(name):
+    from os_check import OSCheck
+    
+    logger.info("Checking for existance of {0} dependency 
package".format(name))
+    is_rpm = not OSCheck.is_ubuntu_family()
+    
+    if is_rpm:
+      is_installed_cmd = ['rpm', '-q'] + [name]
+      install_cmd = ['sudo', 'yum', '-y', 'install'] + [name]
+    else:
+      is_installed_cmd = ['dpkg', '-s'] + [name]
+      install_cmd = ['sudo', 'apt-get', '-y', 'install'] + [name]
+      
+    try:
+      Utils.os_call(is_installed_cmd, logoutput=False)
+      logger.info("Package {0} is already installed. Skipping 
installation.".format(name))
+    except OsCallFailure:
+      logger.info("Package {0} is not installed. Installing 
it...".format(name))
+      Utils.os_call(install_cmd)
+    
+  
+class FakePropertiesHeader(object):
+  """
+  Hacky class to parse properties file without sections.
+  see 
http://stackoverflow.com/questions/2819696/module-to-use-when-parsing-properties-file-in-python/2819788#2819788
+  """
+  FAKE_SECTION_NAME = 'section'
+  def __init__(self, fp):
+    self.fp = fp
+    self.sechead = '[{0}]\n'.format(FakePropertiesHeader.FAKE_SECTION_NAME)
+  def readline(self):
+    if self.sechead:
+      try: 
+        return self.sechead
+      finally: 
+        self.sechead = None
+    else: 
+      return self.fp.readline()
+  
 class OsCallFailure(RuntimeError):
   pass
 
 class Installer:
-  def __init__(self, archive_url, root_folder, verbose):
+  def __init__(self, archive_url, root_folder, verbose, skip_dependencies):
     splited_url = archive_url.split('/')
     self.archive_name = splited_url[-1]
     self.base_url = '/'.join(splited_url[0:-1])
     self.root_folder = root_folder
     self.verbose = verbose
+    self.skip_dependencies = skip_dependencies
     
-  def download_files(self):
-    for name in [ self.archive_name, PREINST_SCRIPT, PRERM_SCRIPT, 
POSTINST_SCRIPT, POSTRM_SCRIPT]: 
+  def download_files(self, files_list):
+    for name in files_list:
+      dirname = os.path.dirname(name)
+      if dirname:
+        Utils.os_call(["mkdir", "-p", dirname])
+        
       url = "{0}/{1}".format(self.base_url, name)
       logger.info("Downloading {0}".format(url))
       Utils.os_call(["wget", "-O", name, url])
     
   def run(self):
-    self.download_files()
+    self.download_files([self.archive_name] +FILES_TO_DOWNLOAD) # 
[self.archive_name] +
     
+    self.check_dependencies()
     self.run_script(PRERM_SCRIPT, ["remove"]) # in case we are upgrading
     self.run_script(POSTRM_SCRIPT, ["remove"]) # in case we are upgrading
     
@@ -92,6 +147,54 @@ class Installer:
     self.extract_archive()
     self.run_script(POSTINST_SCRIPT, ["configure"])
     
+  def check_dependencies(self):
+    from os_check import OSCheck
+    
+    os_family = OSCheck.get_os_family()
+    os_version = OSCheck.get_os_major_version()
+    
+    is_rpm = not OSCheck.is_ubuntu_family()
+    property_prefix = RPM_DEPENDENCIES_PROPERTY if is_rpm else 
DEB_DEPENDENCIES_PROPERTY
+    
+    cp = ConfigParser.SafeConfigParser()
+    with open(OS_PACKAGE_DEPENDENCIES) as fp:
+      cp.readfp(FakePropertiesHeader(fp))
+      
+    properties = dict(cp.items(FakePropertiesHeader.FAKE_SECTION_NAME))
+    
+    packages_string = None
+    postfixes = [os_family+str(ver) for ver in 
range(int(os_version),0,-1)+['']]+['']
+    for postfix in postfixes:
+      property_name = property_prefix + postfix
+      if property_name in properties:
+        packages_string = properties[property_name]
+        break
+      
+    if packages_string is None:
+      err_msg = "No os dependencies found. "
+      if self.skip_dependencies:
+        logger.warn(err_msg)
+      else:
+        raise Exception(err_msg)
+    
+    packages_string = re.sub('Requires\s*:','',packages_string)
+    packages_string = re.sub('\\\\n','',packages_string)
+    packages_string = re.sub('\s','',packages_string)
+    packages_string = re.sub('[()]','',packages_string)
+    
+    if self.skip_dependencies:
+      var = raw_input("Please confirm you have the following packages 
installed {0} (y/n): ".format(packages_string))
+      if var.lower() != "y" and var.lower() != "yes":
+        raise Exception("User canceled the installation.")
+      return
+    
+    pacakges = packages_string.split(',')
+    
+    for package in pacakges:
+      split_parts = re.split('[><=]', package)
+      package_name = split_parts[0]
+      Utils.install_package(package_name)
+    
   def run_script(self, script_name, args):
     bash_args = []
     if self.verbose:
@@ -112,6 +215,8 @@ class Runner:
                       help="sets output level to more detailed")
     parser.add_option("-r", "--root-folder", dest="root_folder", default="/",
                       help="root folder to install Ambari to. E.g.: /opt")
+    parser.add_option("-d", "--dependencies-skip", dest="skip_dependencies", 
action="store_true",
+                  help="the script won't install the package dependencies. 
Please make sure to install them manually.")
     
     (self.options, args) = parser.parse_args()
     
@@ -138,7 +243,7 @@ class Runner:
     Utils.verbose = self.options.verbose
     
     # TODO: check if ends with tar.gz?
-    targz_installer = TargzInstaller(self.url, self.options.root_folder, 
self.options.verbose)
+    targz_installer = TargzInstaller(self.url, self.options.root_folder, 
self.options.verbose, self.options.skip_dependencies)
     targz_installer.run()
       
 if __name__ == '__main__':

http://git-wip-us.apache.org/repos/asf/ambari/blob/ed492292/ambari-server/pom.xml
----------------------------------------------------------------------
diff --git a/ambari-server/pom.xml b/ambari-server/pom.xml
index 623ddca..b500fb2 100644
--- a/ambari-server/pom.xml
+++ b/ambari-server/pom.xml
@@ -26,10 +26,7 @@
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     <python.ver>python &gt;= 2.6</python.ver>
     <!-- On centos the python xml's are inside python package -->
-    <python.xml.package>${python.ver}</python.xml.package>
-    <deb.python.ver>python (&gt;= 2.6)</deb.python.ver>
     <deb.architecture>amd64</deb.architecture>
-    <deb.dependency.list>openssl, postgresql (&gt;= 8.1), ${deb.python.ver}, 
curl</deb.dependency.list>
     <custom.tests>false</custom.tests>
     
<hdpUrlForCentos6>http://public-repo-1.hortonworks.com/HDP/centos6/2.x/updates/2.1.1.0</hdpUrlForCentos6>
     
<hdpLatestUrl>http://public-repo-1.hortonworks.com/HDP/hdp_urlinfo.json</hdpLatestUrl>
@@ -195,6 +192,19 @@
                 <resource>
                   
<directory>${basedir}/src/main/package/deb/control</directory>
                 </resource>
+                <resource>
+                  <directory>${basedir}/src/main/package</directory>
+                  <includes>
+                    <include>dependencies.properties</include>
+                  </includes>
+                </resource>
+                <resource>
+                  
<directory>${project.basedir}/../ambari-common/src/main/python/ambari_commons</directory>
+                  <includes>
+                    <include>os_check.py</include>
+                    <include>resources/os_family.json</include>
+                  </includes>
+                </resource>
               </resources>
             </configuration>
           </execution>
@@ -309,6 +319,23 @@
       </plugin>
       <plugin>
         <groupId>org.codehaus.mojo</groupId>
+        <artifactId>properties-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <phase>package</phase>
+            <goals>
+              <goal>read-project-properties</goal>
+            </goals>
+            <configuration>
+              <files>
+                
<file>${basedir}/src/main/package/dependencies.properties</file>
+              </files>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
         <artifactId>rpm-maven-plugin</artifactId>
         <version>2.1.4</version>
         <executions>
@@ -326,10 +353,7 @@
           <description>Maven Recipe: RPM Package.</description>
           <autoRequires>no</autoRequires>
           <requires>
-            <require>postgresql-server &gt;= 8.1</require>
-            <require>openssl</require>
-            <require>${python.ver}</require>
-            <require>${python.xml.package}</require>
+            <require>${rpm.dependency.list}</require>
           </requires>
           <postinstallScriptlet>
             <scriptFile>src/main/package/rpm/postinstall.sh</scriptFile>
@@ -738,7 +762,7 @@
     <profile>
       <id>suse11</id>
       <properties>
-        <python.xml.package>python-xml</python.xml.package>
+        <rpm.dependency.list>${rpm.dependency.list.suse}</rpm.dependency.list>
       </properties>
     </profile>
     <profile>

http://git-wip-us.apache.org/repos/asf/ambari/blob/ed492292/ambari-server/src/main/package/dependencies.properties
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/package/dependencies.properties 
b/ambari-server/src/main/package/dependencies.properties
new file mode 100644
index 0000000..01244a8
--- /dev/null
+++ b/ambari-server/src/main/package/dependencies.properties
@@ -0,0 +1,33 @@
+# 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 rega4rding 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.
+
+# Please make sure the format of the file is one of the following
+# rpm.dependency.list=...
+# rpm.dependency.list.[os_family_name]=...
+# rpm.dependency.list.[os_family_name][starting_from_version]=...
+# deb.dependency.list=...
+# deb.dependency.list.[os_family_name]=...
+# deb.dependency.list.[os_family_name][starting_from_version]=...
+# 
+# Examples:
+# rpm.dependency.list.suse=openssl,\nRequires: rpm-python # for all suse 
family os
+# rpm.dependency.list.suse11=curl # for all suse family os higher or equal to 
11.
+#
+# Such a format is respected by install_ambari_tarball.py by default, 
+# however should be encouraged manually in pom.xml.
+
+rpm.dependency.list=postgresql-server >= 8.1,\nRequires: openssl,\nRequires: 
python >= 2.6
+rpm.dependency.list.suse=postgresql-server >= 8.1,\nRequires: 
openssl,\nRequires: python-xml,\nRequires: python >= 2.6
+deb.dependency.list=openssl, postgresql (>= 8.1), python (>= 2.6), curl
\ No newline at end of file

Reply via email to