Selaa lähdekoodia

AMBARI-1108 - PUT call to change the state on host_components collection returns 200 (no op), even though GET with the same predicate returns a number of host_components. (Tom Beerbower via mahadev)

git-svn-id: https://svn.apache.org/repos/asf/incubator/ambari/trunk@1431843 13f79535-47bb-0310-9956-ffa450edef68
Mahadev Konar 12 vuotta sitten
vanhempi
commit
bb45951281
100 muutettua tiedostoa jossa 3008 lisäystä ja 782 poistoa
  1. 11 0
      CHANGES.txt
  2. 2 2
      ambari-agent/conf/unix/ambari-agent.ini
  3. 15 0
      ambari-agent/conf/unix/ambari-env.sh
  4. 21 7
      ambari-agent/pom.xml
  5. 15 0
      ambari-agent/src/main/package/rpm/postinstall.sh
  6. 15 0
      ambari-agent/src/main/package/rpm/preinstall.sh
  7. 3 1
      ambari-agent/src/main/puppet/modules/configgenerator/manifests/configfile.pp
  8. 20 8
      ambari-agent/src/main/puppet/modules/hdp-ganglia/manifests/server.pp
  9. 23 6
      ambari-agent/src/main/puppet/modules/hdp-hadoop/manifests/init.pp
  10. 2 2
      ambari-agent/src/main/puppet/modules/hdp-hadoop/manifests/params.pp
  11. 1 1
      ambari-agent/src/main/puppet/modules/hdp-hbase/manifests/params.pp
  12. 1 1
      ambari-agent/src/main/puppet/modules/hdp-hcat-old/manifests/params.pp
  13. 1 1
      ambari-agent/src/main/puppet/modules/hdp-hive/files/startHiveserver2.sh
  14. 24 21
      ambari-agent/src/main/puppet/modules/hdp-hive/manifests/hive/service_check.pp
  15. 3 3
      ambari-agent/src/main/puppet/modules/hdp-hive/manifests/params.pp
  16. 6 4
      ambari-agent/src/main/puppet/modules/hdp-mysql/files/startMysql.sh
  17. 3 1
      ambari-agent/src/main/puppet/modules/hdp-nagios/manifests/params.pp
  18. 7 4
      ambari-agent/src/main/puppet/modules/hdp-nagios/manifests/server.pp
  19. 1 0
      ambari-agent/src/main/puppet/modules/hdp-nagios/manifests/server/config.pp
  20. 46 10
      ambari-agent/src/main/puppet/modules/hdp-nagios/manifests/server/packages.pp
  21. 3 3
      ambari-agent/src/main/puppet/modules/hdp-nagios/templates/hadoop-services.cfg.erb
  22. 1 1
      ambari-agent/src/main/puppet/modules/hdp-nagios/templates/nagios.cfg.erb
  23. 33 0
      ambari-agent/src/main/puppet/modules/hdp-nagios/templates/resource.cfg.erb
  24. 1 1
      ambari-agent/src/main/puppet/modules/hdp-oozie/manifests/service.pp
  25. 2 2
      ambari-agent/src/main/puppet/modules/hdp-templeton/manifests/params.pp
  26. 9 1
      ambari-agent/src/main/puppet/modules/hdp/lib/puppet/parser/functions/hdp_default.rb
  27. 31 1
      ambari-agent/src/main/puppet/modules/hdp/manifests/params.pp
  28. 2 2
      ambari-agent/src/main/python/ambari_agent/AmbariConfig.py
  29. 15 0
      ambari-agent/src/main/python/ambari_agent/Grep.py
  30. 16 6
      ambari-agent/src/main/python/ambari_agent/Hardware.py
  31. 20 2
      ambari-agent/src/main/python/ambari_agent/NetUtil.py
  32. 60 0
      ambari-agent/src/main/python/ambari_agent/machine.py
  33. 2 2
      ambari-agent/src/main/python/ambari_agent/main.py
  34. 20 9
      ambari-agent/src/main/python/ambari_agent/manifestGenerator.py
  35. 16 2
      ambari-agent/src/main/python/ambari_agent/rolesToClass.dict
  36. 16 0
      ambari-agent/src/main/python/ambari_agent/security.py
  37. 15 0
      ambari-agent/src/main/python/ambari_agent/serviceStates.dict
  38. 15 0
      ambari-agent/src/main/python/ambari_agent/servicesToPidNames.dict
  39. 1 1
      ambari-agent/src/test/python/TestActionQueue.py
  40. 1 1
      ambari-agent/src/test/python/TestNetUtil.py
  41. 2 2
      ambari-project/pom.xml
  42. 15 0
      ambari-server/conf/unix/ambari-env.sh
  43. 17 0
      ambari-server/conf/unix/ambari.properties
  44. 2 2
      ambari-server/derby.log
  45. 13 0
      ambari-server/exclude.xml
  46. 26 20
      ambari-server/pom.xml
  47. 20 1
      ambari-server/sbin/ambari-server
  48. 0 18
      ambari-server/src/examples/spec.json
  49. 17 0
      ambari-server/src/main/conf/ambari.properties
  50. 34 0
      ambari-server/src/main/java/org/apache/ambari/server/DuplicateResourceException.java
  51. 4 0
      ambari-server/src/main/java/org/apache/ambari/server/HostNotFoundException.java
  52. 44 0
      ambari-server/src/main/java/org/apache/ambari/server/ParentObjectNotFoundException.java
  53. 1 0
      ambari-server/src/main/java/org/apache/ambari/server/actionmanager/Stage.java
  54. 48 56
      ambari-server/src/main/java/org/apache/ambari/server/api/handlers/BaseManagementHandler.java
  55. 42 4
      ambari-server/src/main/java/org/apache/ambari/server/api/handlers/CreateHandler.java
  56. 38 5
      ambari-server/src/main/java/org/apache/ambari/server/api/handlers/DeleteHandler.java
  57. 51 16
      ambari-server/src/main/java/org/apache/ambari/server/api/handlers/QueryCreateHandler.java
  58. 53 12
      ambari-server/src/main/java/org/apache/ambari/server/api/handlers/ReadHandler.java
  59. 1 0
      ambari-server/src/main/java/org/apache/ambari/server/api/handlers/RequestHandler.java
  60. 35 4
      ambari-server/src/main/java/org/apache/ambari/server/api/handlers/UpdateHandler.java
  61. 11 7
      ambari-server/src/main/java/org/apache/ambari/server/api/query/Query.java
  62. 16 15
      ambari-server/src/main/java/org/apache/ambari/server/api/query/QueryImpl.java
  63. 32 0
      ambari-server/src/main/java/org/apache/ambari/server/api/resources/RequestResourceDefinition.java
  64. 7 0
      ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstance.java
  65. 5 0
      ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceImpl.java
  66. 241 0
      ambari-server/src/main/java/org/apache/ambari/server/api/services/BaseRequest.java
  67. 29 19
      ambari-server/src/main/java/org/apache/ambari/server/api/services/BaseService.java
  68. 47 0
      ambari-server/src/main/java/org/apache/ambari/server/api/services/DeleteRequest.java
  69. 46 0
      ambari-server/src/main/java/org/apache/ambari/server/api/services/GetRequest.java
  70. 47 0
      ambari-server/src/main/java/org/apache/ambari/server/api/services/PostRequest.java
  71. 47 0
      ambari-server/src/main/java/org/apache/ambari/server/api/services/PutRequest.java
  72. 59 0
      ambari-server/src/main/java/org/apache/ambari/server/api/services/QueryPostRequest.java
  73. 0 7
      ambari-server/src/main/java/org/apache/ambari/server/api/services/Request.java
  74. 14 9
      ambari-server/src/main/java/org/apache/ambari/server/api/services/RequestFactory.java
  75. 40 2
      ambari-server/src/main/java/org/apache/ambari/server/api/services/Result.java
  76. 30 0
      ambari-server/src/main/java/org/apache/ambari/server/api/services/ResultImpl.java
  77. 5 0
      ambari-server/src/main/java/org/apache/ambari/server/api/services/ResultPostProcessorImpl.java
  78. 176 0
      ambari-server/src/main/java/org/apache/ambari/server/api/services/ResultStatus.java
  79. 45 0
      ambari-server/src/main/java/org/apache/ambari/server/api/services/persistence/PersistenceManager.java
  80. 94 0
      ambari-server/src/main/java/org/apache/ambari/server/api/services/persistence/PersistenceManagerImpl.java
  81. 35 9
      ambari-server/src/main/java/org/apache/ambari/server/api/services/serializers/JsonSerializer.java
  82. 12 4
      ambari-server/src/main/java/org/apache/ambari/server/api/services/serializers/ResultSerializer.java
  83. 28 1
      ambari-server/src/main/java/org/apache/ambari/server/bootstrap/BSHostStatusCollector.java
  84. 9 1
      ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java
  85. 3 1
      ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java
  86. 331 135
      ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
  87. 70 52
      ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
  88. 11 21
      ambari-server/src/main/java/org/apache/ambari/server/controller/HostRequest.java
  89. 10 9
      ambari-server/src/main/java/org/apache/ambari/server/controller/HostResponse.java
  90. 5 1
      ambari-server/src/main/java/org/apache/ambari/server/controller/ganglia/GangliaHostProvider.java
  91. 20 7
      ambari-server/src/main/java/org/apache/ambari/server/controller/ganglia/GangliaPropertyProvider.java
  92. 24 12
      ambari-server/src/main/java/org/apache/ambari/server/controller/ganglia/GangliaReportPropertyProvider.java
  93. 18 0
      ambari-server/src/main/java/org/apache/ambari/server/controller/ganglia/MetricsMapping.java
  94. 38 16
      ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ActionResourceProvider.java
  95. 126 83
      ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterControllerImpl.java
  96. 54 20
      ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterResourceProvider.java
  97. 57 26
      ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ComponentResourceProvider.java
  98. 97 22
      ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ConfigurationResourceProvider.java
  99. 17 17
      ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java
  100. 90 40
      ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostComponentResourceProvider.java

+ 11 - 0
CHANGES.txt

@@ -8,6 +8,17 @@ should be listed by their full name.
 
   Merging AMBARI-666 to trunk.
 
+ INCOMPATIBLE CHANGES
+ 
+ NEW FEATURES
+
+ AMBARI-1108 - PUT call to change the state on host_components collection
+ returns 200 (no op), even though GET with the same predicate returns a number
+ of host_components. (Tom Beerbower via mahadev)
+
+ BUG FIXES
+
+
 AMBARI-666 branch (unreleased changes)
 
   INCOMPATIBLE CHANGES

+ 2 - 2
ambari-agent/conf/unix/ambari-agent.ini

@@ -1,7 +1,7 @@
 [server]
 hostname=localhost
-url_port=4080
-secured_url_port=8443
+url_port=8440
+secured_url_port=8441
 
 [agent]
 prefix=/var/lib/ambari-agent/data

+ 15 - 0
ambari-agent/conf/unix/ambari-env.sh

@@ -1,3 +1,18 @@
+# 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
+
 # To change a passphrase used by the agent adjust the line below. This value is used when no passphrase is
 # given through environment variable
 AMBARI_PASSPHRASE="DEV"

+ 21 - 7
ambari-agent/pom.xml

@@ -19,21 +19,21 @@
   <parent>
     <groupId>org.apache.ambari</groupId>
     <artifactId>ambari-project</artifactId>
-    <version>1.0.3-SNAPSHOT</version>
+    <version>1.2.0-SNAPSHOT</version>
     <relativePath>../ambari-project</relativePath>
   </parent>
   <modelVersion>4.0.0</modelVersion>
   <groupId>org.apache.ambari</groupId>
   <artifactId>ambari-agent</artifactId>
   <packaging>pom</packaging>
-  <version>1.0.3-SNAPSHOT</version>
+  <version>1.2.0-SNAPSHOT</version>
   <name>Ambari Agent</name>
   <description>Ambari Agent</description>
   <properties>
     <final.name>${project.artifactId}-${project.version}</final.name>
     <package.release>1</package.release>
     <package.prefix>/usr</package.prefix>
-    <package.conf.dir>/etc/ambari-agent</package.conf.dir>
+    <package.conf.dir>/etc/ambari-agent/conf</package.conf.dir>
     <package.log.dir>/var/log/ambari-agent</package.log.dir>
     <package.pid.dir>/var/run/ambari-agent</package.pid.dir>
     <skipTests>false</skipTests>
@@ -181,7 +181,7 @@
               </sources>
             </mapping>
             <mapping>
-              <directory>/etc/ambari-agent</directory>
+              <directory>${package.conf.dir}</directory>
               <filemode>755</filemode>
               <username>root</username>
               <groupname>root</groupname>
@@ -193,7 +193,7 @@
             </mapping>
             <mapping>
               <directory>/usr/sbin</directory>
-              <filemode>744</filemode>
+              <filemode>755</filemode>
               <username>root</username>
               <groupname>root</groupname>
               <sources>
@@ -214,7 +214,7 @@
               </sources>
             </mapping>
             <mapping>
-              <directory>/var/run/ambari-agent</directory>
+              <directory>${package.pid.dir}</directory>
               <filemode>755</filemode>
               <username>root</username>
               <groupname>root</groupname>
@@ -232,7 +232,7 @@
               <groupname>root</groupname>
             </mapping>
             <mapping>
-              <directory>/var/log/ambari-agent</directory>
+              <directory>${package.log.dir}</directory>
               <filemode>755</filemode>
               <username>root</username>
               <groupname>root</groupname>
@@ -280,6 +280,20 @@
           </execution>
         </executions>
       </plugin>
+        <plugin>
+            <groupId>org.apache.rat</groupId>
+            <artifactId>apache-rat-plugin</artifactId>
+            <version>0.8</version>
+            <configuration>
+                <excludes>
+                    <exclude>src/test/python/dummy*.txt</exclude>
+                </excludes>
+                <includes>
+                    <include>pom.xml</include>
+                </includes>
+            </configuration>
+        </plugin>
+
     </plugins>
     <extensions>
       <extension>

+ 15 - 0
ambari-agent/src/main/package/rpm/postinstall.sh

@@ -1 +1,16 @@
+# 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
+
 chmod 755 /usr/lib/ambari-agent/lib/facter-1.6.10/bin/facter /usr/lib/ambari-agent/lib/puppet-2.7.9/bin/filebucket /usr/lib/ambari-agent/lib/puppet-2.7.9/bin/pi /usr/lib/ambari-agent/lib/puppet-2.7.9/bin/puppet /usr/lib/ambari-agent/lib/puppet-2.7.9/bin/puppetdoc /usr/lib/ambari-agent/lib/puppet-2.7.9/bin/ralsh /usr/lib/ambari-agent/lib/ruby-1.8.7-p370/bin/*

+ 15 - 0
ambari-agent/src/main/package/rpm/preinstall.sh

@@ -1,2 +1,17 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License
+
 getent group puppet >/dev/null || groupadd -r puppet
 getent passwd puppet >/dev/null || /usr/sbin/useradd -g puppet puppet

+ 3 - 1
ambari-agent/src/main/puppet/modules/configgenerator/manifests/configfile.pp

@@ -43,7 +43,7 @@
 # Note: Set correct $modulespath in the configgenerator (or pass it as parameter)
 #
 
-define configgenerator::configfile ($modulespath='/etc/puppet/modules', $filename, $module, $configuration) {
+define configgenerator::configfile ($modulespath='/etc/puppet/modules', $filename, $module, $configuration, $owner = "root", $group = "root") {
   $configcontent = inline_template('<!--<%=Time.now.asctime %>-->
   <configuration>
   <% configuration.each do |key,value| -%>
@@ -61,5 +61,7 @@ file {"${modulespath}/${filename}":
   ensure  => present,
   content => $configcontent,
   path => "${modulespath}/${filename}",
+  owner => $owner,
+  group => $group
 }
 } 

+ 20 - 8
ambari-agent/src/main/puppet/modules/hdp-ganglia/manifests/server.pp

@@ -63,8 +63,11 @@ class hdp-ganglia::server(
   
   if ($service_state == 'installed_and_configured') {
     $webserver_state = 'restart'
+  } elsif ($service_state == 'running') {
+    $webserver_state = 'running'
   } else {
-    $webserver_state = $service_state
+    # We are never stopping httpd
+    #$webserver_state = $service_state
   }
 
   class { 'hdp-monitor-webserver': service_state => $webserver_state}
@@ -87,12 +90,19 @@ class hdp-ganglia::server::packages(
   hdp::package { ['ganglia-server','ganglia-gweb','ganglia-hdp-gweb-addons']: 
     ensure      => $ensure,
     java_needed => false  
-  } 
+  }
+
+  hdp::package { ['rrdtool']:
+        ensure      => 'absent',
+        java_needed => false,
+        before => Hdp::Package ['rrdtool-python']
+  }
+
+  hdp::package { ['rrdtool-python']:
+      ensure      => $ensure,
+      java_needed => false
+  }
 
-  hdp::package { ['rrdtool-python']: 
-    ensure      => $ensure,
-    java_needed => false  
-  } 
 }
 
 class hdp-ganglia::server::files(
@@ -101,12 +111,14 @@ class hdp-ganglia::server::files(
 {
 
 
-  $rrd_py_path = $hdp::params::rrd_py_path
+  $rrd_py_path = $hdp::params::rrd_py_path [$hdp::params::hdp_os_type]
   hdp::directory_recursive_create{$rrd_py_path:
     ensure => "directory"  
   }
 
-  file{'/var/www/cgi-bin/rrd.py' : 
+  $rrd_py_file_path = "${rrd_py_path}/rrd.py"
+
+  file{$rrd_py_file_path :
     ensure => $ensure,
     source => "puppet:///modules/hdp-ganglia/rrd.py",
     mode   => '0755',

+ 23 - 6
ambari-agent/src/main/puppet/modules/hdp-hadoop/manifests/init.pp

@@ -48,7 +48,14 @@ debug('##Configs generation for hdp-hadoop')
       modulespath => $hdp-hadoop::params::conf_dir,
       filename => 'mapred-queue-acls.xml',
       module => 'hdp-hadoop',
-      configuration => $configuration['mapred-queue-acls']
+      configuration => $configuration['mapred-queue-acls'],
+      owner => $hdp-hadoop::params::mapred_user,
+      group => $hdp::params::hadoop_user_group
+    }
+  } else { # Manually overriding ownership of file installed by hadoop package
+    file { "${hdp-hadoop::params::conf_dir}/mapred-queue-acls.xml":
+      owner => $hdp-hadoop::params::mapred_user,
+      group => $hdp::params::hadoop_user_group
     }
   }
   
@@ -57,7 +64,9 @@ debug('##Configs generation for hdp-hadoop')
       modulespath => $hdp-hadoop::params::conf_dir,
       filename => 'hadoop-policy.xml',
       module => 'hdp-hadoop',
-      configuration => $configuration['hadoop-policy']
+      configuration => $configuration['hadoop-policy'],
+      owner => $hdp-hadoop::params::hdfs_user,
+      group => $hdp::params::hadoop_user_group
     }
   }
 
@@ -66,7 +75,9 @@ debug('##Configs generation for hdp-hadoop')
         modulespath => $hdp-hadoop::params::conf_dir,
         filename => 'core-site.xml',
         module => 'hdp-hadoop',
-        configuration => $configuration['core-site']
+        configuration => $configuration['core-site'],
+        owner => $hdp-hadoop::params::hdfs_user,
+        group => $hdp::params::hadoop_user_group
       }
     }
 
@@ -75,7 +86,9 @@ debug('##Configs generation for hdp-hadoop')
       modulespath => $hdp-hadoop::params::conf_dir,
       filename => 'mapred-site.xml',
       module => 'hdp-hadoop',
-      configuration => $configuration['mapred-site']
+      configuration => $configuration['mapred-site'],
+      owner => $hdp-hadoop::params::mapred_user,
+      group => $hdp::params::hadoop_user_group
     }
   }
   
@@ -84,7 +97,9 @@ debug('##Configs generation for hdp-hadoop')
       modulespath => $hdp-hadoop::params::conf_dir,
       filename => 'capacity-scheduler.xml',
       module => 'hdp-hadoop',
-      configuration => $configuration['capacity-scheduler']
+      configuration => $configuration['capacity-scheduler'],
+      owner => $hdp-hadoop::params::hdfs_user,
+      group => $hdp::params::hadoop_user_group
     }
   }
 
@@ -93,7 +108,9 @@ debug('##Configs generation for hdp-hadoop')
       modulespath => $hdp-hadoop::params::conf_dir,
       filename => 'hdfs-site.xml',
       module => 'hdp-hadoop',
-      configuration => $configuration['hdfs-site']
+      configuration => $configuration['hdfs-site'],
+      owner => $hdp-hadoop::params::hdfs_user,
+      group => $hdp::params::hadoop_user_group
     }
   }
 

+ 2 - 2
ambari-agent/src/main/puppet/modules/hdp-hadoop/manifests/params.pp

@@ -120,7 +120,7 @@ class hdp-hadoop::params(
 
   $dfs_support_append = hdp_default("hadoop/hdfs-site/dfs_support_append",true)
 
-  $dfs_webhdfs_enabled = hdp_default("hadoop/hdfs-site/dfs_webhdfs_enabled","false")
+  $dfs_webhdfs_enabled = hdp_default("hadoop/hdfs-site/dfs_webhdfs_enabled",false)
 
 
  ######### mapred #######
@@ -171,7 +171,7 @@ class hdp-hadoop::params(
   $task_bin_exe = hdp_default("hadoop/health_check/task_bin_exe")
 
   $rca_enabled = hdp_default("rca_enabled", false)
-  if ($rca_enabled == true or $rca_enabled == "true") {
+  if ($rca_enabled == true) {
     $rca_prefix = ""
   } else {
     $rca_prefix = "###"

+ 1 - 1
ambari-agent/src/main/puppet/modules/hdp-hbase/manifests/params.pp

@@ -47,7 +47,7 @@ class hdp-hbase::params() inherits hdp::params
   #TODO: check if any of these 'hdfs' vars need to be euated with vars in hdp-hadoop
   $hdfs_enable_shortcircuit_read = hdp_default("hadoop/hbase-site/hdfs_enable_shortcircuit_read",true)
 
-  $hdfs_enable_shortcircuit_skipchecksum = hdp_default("hadoop/hbase-site/hdfs_enable_shortcircuit_skipchecksum","false")
+  $hdfs_enable_shortcircuit_skipchecksum = hdp_default("hadoop/hbase-site/hdfs_enable_shortcircuit_skipchecksum",false)
 
   $hdfs_support_append = hdp_default("hadoop/hbase-site/hdfs_support_append",true)
 

+ 1 - 1
ambari-agent/src/main/puppet/modules/hdp-hcat-old/manifests/params.pp

@@ -47,7 +47,7 @@ class hdp-hcat::params() inherits hdp::params
 
   $hcat_metastore_principal = hdp_default("hadoop/hive-site/hcat_metastore_principal")
 
-  $hcat_metastore_sasl_enabled = hdp_default("hadoop/hive-site/hcat_metastore_sasl_enabled","false")
+  $hcat_metastore_sasl_enabled = hdp_default("hadoop/hive-site/hcat_metastore_sasl_enabled",false)
 
   #TODO: using instead hcat_server_host in hdp::params $hcat_metastore_server_host = hdp_default("hadoop/hive-site/hcat_metastore_server_host")
 

+ 1 - 1
ambari-agent/src/main/puppet/modules/hdp-hive/files/startHiveserver2.sh

@@ -18,5 +18,5 @@
 # under the License.
 #
 #
-/usr/lib/hive/bin/hiveserver2 > $1 2> $2 &
+/usr/lib/hive/bin/hiveserver2 -hiveconf hive.metastore.uris=' ' > $1 2> $2 &
 echo $!|cat>$3

+ 24 - 21
ambari-agent/src/main/puppet/modules/hdp-hive/manifests/hive/service_check.pp

@@ -48,30 +48,33 @@ class hdp-hive::hive::service_check() inherits hdp-hive::params
     user => $smoke_test_user
   }
 
-  $unique = hdp_unique_id_and_date()
-  $output_file = "/apps/hive/warehouse/hivesmoke${unique}"
-  $test_cmd = "fs -test -e ${output_file}"
+#  $unique = hdp_unique_id_and_date()
+#  $output_file = "/apps/hive/warehouse/hivesmoke${unique}"
+#  $test_cmd = "fs -test -e ${output_file}"
 
-  file { '/tmp/hiveSmoke.sh':
-    ensure => present,
-    source => "puppet:///modules/hdp-hive/hiveSmoke.sh",
-    mode => '0755',
-  }
+#  file { '/tmp/hiveSmoke.sh':
+#    ensure => present,
+#    source => "puppet:///modules/hdp-hive/hiveSmoke.sh",
+#    mode => '0755',
+#  }
+#
+#  exec { '/tmp/hiveSmoke.sh':
+#    command => "su - ${smoke_test_user} -c 'env JAVA_HOME=$hdp::params::java64_home sh /tmp/hiveSmoke.sh hivesmoke${unique}'",
+#    tries => 3,
+#    try_sleep => 5,
+#    path => '/usr/sbin:/sbin:/usr/local/bin:/bin:/usr/bin',
+#    notify => Hdp-hadoop::Exec-hadoop['hive::service_check::test'],
+#    logoutput => "true"
+#  }
 
-  exec { '/tmp/hiveSmoke.sh':
-    command => "su - ${smoke_test_user} -c 'env JAVA_HOME=$hdp::params::java64_home sh /tmp/hiveSmoke.sh hivesmoke${unique}'",
-    tries => 3,
-    try_sleep => 5,
-    path => '/usr/sbin:/sbin:/usr/local/bin:/bin:/usr/bin',
-    notify => Hdp-hadoop::Exec-hadoop['hive::service_check::test'],
-    logoutput => "true"
-  }
+#  hdp-hadoop::exec-hadoop { 'hive::service_check::test':
+#    command => $test_cmd,
+#    refreshonly => true
+#  }
 
-  hdp-hadoop::exec-hadoop { 'hive::service_check::test':
-    command => $test_cmd,
-    refreshonly => true
-  }
+#  File[$smoke_test_path] -> File[$smoke_test_sql] -> Exec[$smoke_test_path] -> File['/tmp/hiveSmoke.sh'] -> Exec['/tmp/hiveSmoke.sh'] -> Hdp-Hadoop::Exec-Hadoop['hive::service_check::test']
 
-  File[$smoke_test_path] -> File[$smoke_test_sql] -> Exec[$smoke_test_path] -> File['/tmp/hiveSmoke.sh'] -> Exec['/tmp/hiveSmoke.sh'] -> Hdp-Hadoop::Exec-Hadoop['hive::service_check::test']
+  include hdp-hcat::hcat::service_check  
 
+  File[$smoke_test_path] -> File[$smoke_test_sql] -> Exec[$smoke_test_path]
 }

+ 3 - 3
ambari-agent/src/main/puppet/modules/hdp-hive/manifests/params.pp

@@ -32,7 +32,7 @@ class hdp-hive::params() inherits hdp::params
   $hive_metastore_port = hdp_default("hive_metastore_port",9083)
   $hive_lib = hdp_default("hive_lib","/usr/lib/hive/lib/") #TODO: should I remove and just use hive_dbroot
   $hive_var_lib = hdp_default("hive_var_lib","/var/lib/hive")  
-  $hive_url = 'jdbc:hive2://localhost:10000'
+  $hive_url = "jdbc:hive2://${hive_server_host}:10000"
 
   ### hive-env
   $hive_conf_dir = $hdp::params::hive_conf_dir
@@ -49,9 +49,9 @@ class hdp-hive::params() inherits hdp::params
   $hive_database_name = hdp_default("hadoop/hive-site/hive_database_name","hive")
 
   if ($hdp::params::security_enabled == true) {
-    $hive_metastore_sasl_enabled = "true"
+    $hive_metastore_sasl_enabled = true
   } else {
-    $hive_metastore_sasl_enabled = "false"
+    $hive_metastore_sasl_enabled = false
   }
 
   $keytab_path = hdp_default("keytab_path","/etc/security/keytabs")

+ 6 - 4
ambari-agent/src/main/puppet/modules/hdp-mysql/files/startMysql.sh

@@ -24,7 +24,9 @@ mysqldbuser=$1
 mysqldbpasswd=$2
 mysqldbhost=$3
 
-echo "Adding user $mysqldbuser@$mysqldbhost"
-echo "CREATE USER '$mysqldbuser'@'$mysqldbhost' IDENTIFIED BY '$mysqldbpasswd';" > mysql -u root
-echo "GRANT ALL PRIVILEGES ON *.* TO '$mysqldbuser'@'$mysqldbhost';" > mysql -u root
-echo "flush privileges;" > mysql -u root
+echo "Adding user $mysqldbuser@$mysqldbhost and $mysqldbuser@localhost"
+mysql -u root -e "CREATE USER '$mysqldbuser'@'$mysqldbhost' IDENTIFIED BY '$mysqldbpasswd';"
+mysql -u root -e "CREATE USER '$mysqldbuser'@'localhost' IDENTIFIED BY '$mysqldbpasswd';"
+mysql -u root -e "GRANT ALL PRIVILEGES ON *.* TO '$mysqldbuser'@'$mysqldbhost';"
+mysql -u root -e "GRANT ALL PRIVILEGES ON *.* TO '$mysqldbuser'@'localhost';"
+mysql -u root -e "flush privileges;"

+ 3 - 1
ambari-agent/src/main/puppet/modules/hdp-nagios/manifests/params.pp

@@ -27,6 +27,7 @@ class hdp-nagios::params() inherits hdp::params
   $conf_dir = hdp_default("nagios_conf_dir","/etc/nagios")
 
   $plugins_dir = "/usr/lib64/nagios/plugins"
+  $eventhandlers_dir = "/usr/lib64/nagios/eventhandlers"  # Does not exist yet
   $nagios_pid_dir = "/var/run/nagios"
 
   $nagios_obj_dir = hdp_default("nagios_obj_dir","/etc/nagios/objects")
@@ -37,7 +38,8 @@ class hdp-nagios::params() inherits hdp::params
   $nagios_servicegroup_cfg = hdp_default("nagios_servicegroup_cfg","${nagios_obj_dir}/hadoop-servicegroups.cfg")
   $nagios_service_cfg = hdp_default("nagios_service_cfg","${nagios_obj_dir}/hadoop-services.cfg")
   $nagios_command_cfg = hdp_default("nagios_command_cfg","${nagios_obj_dir}/hadoop-commands.cfg")
-  
+  $nagios_resource_cfg = hdp_default("nagios_resource_cfg","${conf_dir}/resource.cfg")
+
   $nagios_web_login = hdp_default("nagios_web_login","nagiosadmin")
   $nagios_web_password = hdp_default("nagios_web_password","admin")
   

+ 7 - 4
ambari-agent/src/main/puppet/modules/hdp-nagios/manifests/server.pp

@@ -98,7 +98,7 @@ class hdp-nagios::server(
      Class['hdp-nagios::server::packages'] -> Exec['rm -f /var/nagios/rw/nagios.cmd'] -> Hdp::Directory[$nagios_config_dir] -> Hdp::Directory[$plugins_dir] -> Hdp::Directory[$nagios_obj_dir] ->  Hdp::Directory_recursive_create[$nagios_pid_dir] -> Hdp::Directory[$nagios_var_dir]
 
   } elsif ($service_state in ['running','stopped','installed_and_configured']) {
-    class { 'hdp-nagios::server::packages' : }
+    class { 'hdp-nagios::server::packages' : service_state => $service_state}
 
     hdp::directory { $nagios_config_dir:
       service_state => $service_state,
@@ -114,7 +114,7 @@ class hdp-nagios::server(
       service_state => $service_state,
       force => true
     }
-	
+
 	hdp::directory_recursive_create { $nagios_pid_dir:
       service_state => $service_state,
       owner => $nagios_user,
@@ -146,10 +146,13 @@ class hdp-nagios::server(
       group => $hdp-nagios::params::nagios_group
     }
 	
-   if ($service_state == 'installed_and_configured') {
+    if ($service_state == 'installed_and_configured') {
       $webserver_state = 'restart'
+    } elsif ($service_state == 'running') {
+      $webserver_state = 'running'
     } else {
-      $webserver_state = $service_state
+      # We are never stopping httpd
+      #$webserver_state = $service_state
     }
 
     class { 'hdp-monitor-webserver': service_state => $webserver_state}

+ 1 - 0
ambari-agent/src/main/puppet/modules/hdp-nagios/manifests/server/config.pp

@@ -24,6 +24,7 @@ class hdp-nagios::server::config()
   $host_cfg = $hdp-nagios::params::nagios_host_cfg
   
   hdp-nagios::server::configfile { 'nagios.cfg': conf_dir => $hdp-nagios::params::conf_dir }
+  hdp-nagios::server::configfile { 'resource.cfg': conf_dir => $hdp-nagios::params::conf_dir }
   hdp-nagios::server::configfile { 'hadoop-hosts.cfg': }
   hdp-nagios::server::configfile { 'hadoop-hostgroups.cfg': }
   hdp-nagios::server::configfile { 'hadoop-servicegroups.cfg': }

+ 46 - 10
ambari-agent/src/main/puppet/modules/hdp-nagios/manifests/server/packages.pp

@@ -28,17 +28,53 @@ class hdp-nagios::server::packages(
       ensure => 'uninstalled'
     }
   } elsif ($service_state in ['running','stopped','installed_and_configured']) {
-        hdp-nagios::server::package { ['nagios-server','nagios-fping','nagios-plugins','nagios-addons','nagios-php-pecl-json']:
-          ensure => 'present'
-    }
-  } 
-  Hdp-nagios::Server::Package['nagios-server'] -> Hdp::Package['nagios-plugins'] #other order produces package conflict
-  Hdp-nagios::Server::Package['nagios-plugins'] -> Hdp::Package['nagios-addons'] #other order produces package conflict
+  
+
+  
+  if ($service_state == 'installed_and_configured') {
+    package{'nagios-plugins-process-old':
+      name   => 'nagios-plugins',
+      ensure => absent}
+  }
+	
+  hdp::package { 'nagios-server': 
+    ensure      => present,
+    java_needed => false
+  }
+  
+  hdp::package { 'nagios-fping': 
+    ensure      => present,
+    java_needed => false
+  }
+  
+  hdp::package { 'nagios-addons': 
+    ensure      => present,
+    java_needed => false
+  }
+	
+  hdp::package { 'nagios-plugins': 
+    ensure      => present,
+    java_needed => false
+  }
+  
+  hdp::package { 'nagios-php-pecl-json': 
+    ensure      => present,
+    java_needed => false
+  }
+  
+  
+debug("## state: $service_state")
+  if ($service_state == 'installed_and_configured') {
+    debug("##Adding removing dep")
+    Package['nagios-plugins-process-old'] -> Hdp::Package['nagios-plugins']
+  }
+
+  Hdp::Package['nagios-plugins'] -> Hdp::Package['nagios-server'] -> Hdp::Package['nagios-fping'] -> Hdp::Package['nagios-addons'] -> Hdp::Package['nagios-php-pecl-json']
+
+    
+
+} 
 
-  anchor{'hdp-nagios::server::packages::begin':} -> Hdp-nagios::Server::Package<||> -> anchor{'hdp-nagios::server::packages::end':}
-  Anchor['hdp-nagios::server::packages::begin'] -> Hdp::Package['nagios-server'] ->
-      Hdp::Package['nagios-addons'] -> Anchor['hdp-nagios::server::packages::end']
-  Hdp-nagios::Server::Package['nagios-fping'] -> Hdp-nagios::Server::Package['nagios-plugins']
 }
 
 

+ 3 - 3
ambari-agent/src/main/puppet/modules/hdp-nagios/templates/hadoop-services.cfg.erb

@@ -422,7 +422,7 @@ define service {
         use                     hadoop-service
         service_description     HIVE-METASTORE::HIVE-METASTORE status check
         servicegroups           HIVE-METASTORE
-        <%if scope.function_hdp_template_var("security_enabled") == "true"-%>
+        <%if scope.function_hdp_template_var("security_enabled")-%>
         check_command           check_hive_metastore_status!9083!<%=scope.function_hdp_template_var("java64_home")%>!true!<%=scope.function_hdp_template_var("keytab_path")%>/<%=scope.function_hdp_template_var("nagios_user")%>.headless.keytab!<%=scope.function_hdp_template_var("nagios_user")%>
         <%else-%>
         check_command           check_hive_metastore_status!9083!<%=scope.function_hdp_template_var("java64_home")%>!false
@@ -439,7 +439,7 @@ define service {
         use                     hadoop-service
         service_description     OOZIE::Oozie status check
         servicegroups           OOZIE
-        <%if scope.function_hdp_template_var("security_enabled") == "true" -%>
+        <%if scope.function_hdp_template_var("security_enabled")-%>
         check_command           check_oozie_status!11000!<%=scope.function_hdp_template_var("java64_home")%>!true!<%=scope.function_hdp_template_var("keytab_path")%>/<%=scope.function_hdp_template_var("nagios_user")%>.headless.keytab!<%=scope.function_hdp_template_var("nagios_user")%>
         <%else-%>
         check_command           check_oozie_status!11000!<%=scope.function_hdp_template_var("java64_home")%>!false
@@ -456,7 +456,7 @@ define service {
         use                     hadoop-service
         service_description     TEMPLETON::Templeton status check
         servicegroups           TEMPLETON
-        <%if scope.function_hdp_template_var("security_enabled") == "true"-%>
+        <%if scope.function_hdp_template_var("security_enabled")-%>
         check_command           check_templeton_status!50111!v1!true!<%=scope.function_hdp_template_var("keytab_path")%>/<%=scope.function_hdp_template_var("nagios_user")%>.headless.keytab!<%=scope.function_hdp_template_var("nagios_user")%>
         <%else-%>
         check_command           check_templeton_status!50111!v1!false

+ 1 - 1
ambari-agent/src/main/puppet/modules/hdp-nagios/templates/nagios.cfg.erb

@@ -120,7 +120,7 @@ precached_object_file=/var/nagios/objects.precache
 # defined as macros in this file and restrictive permissions (600)
 # can be placed on this file.
 
-resource_file=/etc/nagios/resource.cfg
+resource_file=<%=scope.function_hdp_template_var("nagios_resource_cfg")%>
 
 
 

+ 33 - 0
ambari-agent/src/main/puppet/modules/hdp-nagios/templates/resource.cfg.erb

@@ -0,0 +1,33 @@
+###########################################################################
+#
+# RESOURCE.CFG - Sample Resource File for Nagios 3.2.3
+#
+# Last Modified: 09-10-2003
+#
+# You can define $USERx$ macros in this file, which can in turn be used
+# in command definitions in your host config file(s).  $USERx$ macros are
+# useful for storing sensitive information such as usernames, passwords,
+# etc.  They are also handy for specifying the path to plugins and
+# event handlers - if you decide to move the plugins or event handlers to
+# a different directory in the future, you can just update one or two
+# $USERx$ macros, instead of modifying a lot of command definitions.
+#
+# The CGIs will not attempt to read the contents of resource files, so
+# you can set restrictive permissions (600 or 660) on them.
+#
+# Nagios supports up to 32 $USERx$ macros ($USER1$ through $USER32$)
+#
+# Resource files may also be used to store configuration directives for
+# external data sources like MySQL...
+#
+###########################################################################
+
+# Sets $USER1$ to be the path to the plugins
+$USER1$=<%=scope.function_hdp_template_var("plugins_dir")%>
+
+# Sets $USER2$ to be the path to event handlers
+#$USER2$=<%=scope.function_hdp_template_var("eventhandlers_dir")%>
+
+# Store some usernames and passwords (hidden from the CGIs)
+#$USER3$=someuser
+#$USER4$=somepassword

+ 1 - 1
ambari-agent/src/main/puppet/modules/hdp-oozie/manifests/service.pp

@@ -34,7 +34,7 @@ class hdp-oozie::service(
   $jar_location = $hdp::params::hadoop_jar_location
   $ext_js_path = "/usr/share/HDP-oozie/ext.zip"
   
-  if ($lzo_enabled) {
+  if ($lzo_enabled == true) {
     $lzo_jar_suffix = "-jars /usr/lib/hadoop/lib/hadoop-lzo-0.5.0.jar"
   } else {
     $lzo_jar_suffix = ""

+ 2 - 2
ambari-agent/src/main/puppet/modules/hdp-templeton/manifests/params.pp

@@ -45,14 +45,14 @@ class hdp-templeton::params() inherits hdp::params
   
   ### templeton-site
   $hadoop_conf_dir = hdp_default("hadoop/templeton-site/hadoop_conf_dir")
-  $templeton_jar = hdp_default("hadoop/templeton-site/templeton_jar","/usr/share/templeton/templeton-0.1.4.14.jar")
+  $templeton_jar = hdp_default("hadoop/templeton-site/templeton_jar","/usr/lib/hcatalog/share/webhcat/svr/webhcat.jar")
   $zookeeper_jar = hdp_default("hadoop/templeton-site/zookeeper_jar","/usr/lib/zookeeper/zookeeper.jar")
   $pig_tar_gz = hdp_default("hadoop/templeton-site/pig_tar_gz","$dest_pig_tar_name")
   $pig_tar_name_hdfs = hdp_default("hadoop/templeton-site/pig_tar_name_hdfs","pig-0.9.2.14")
 
   $hive_tar_gz = hdp_default("hadoop/templeton-site/hive_tar_gz","$dest_hive_tar_name")
   $hive_tar_gz_name = hdp_default("hadoop/templeton-site/hive_tar_gz_name","hive-0.9.0.14")
-  $hive_metastore_sasl_enabled = hdp_default("hadoop/templeton-site/hive_metastore_sasl_enabled","no")
+  $hive_metastore_sasl_enabled = hdp_default("hadoop/templeton-site/hive_metastore_sasl_enabled",false)
 
   $templeton_metastore_principal = hdp_default("hadoop/templeton-site/templeton_metastore_principal")
 

+ 9 - 1
ambari-agent/src/main/puppet/modules/hdp/lib/puppet/parser/functions/hdp_default.rb

@@ -25,7 +25,15 @@ module Puppet::Parser::Functions
     var_name = scoped_var_name.split("/").last
     default = args[1]
     val = lookupvar("::#{var_name}")
-    function_hdp_is_empty(val) ? (default||"") : val
+    # To workaround string-boolean comparison issues,
+    # ensure that we return boolean result if the default value
+    # is also boolean
+    if default == true or default == false # we expect boolean value as a result
+      casted_val = (val == "true" or val == true) # converting to boolean
+    else # default
+      casted_val = val
+    end
+    function_hdp_is_empty(val) ? (default||"") : casted_val
   end
 end
 

+ 31 - 1
ambari-agent/src/main/puppet/modules/hdp/manifests/params.pp

@@ -305,6 +305,16 @@ class hdp::params()
     rrdtool-python => {
       64 => ['python-rrdtool.x86_64']
     },
+    # The 32bit version of package rrdtool is removed on centos 5/6 to prevent conflict ( BUG-2408)
+    rrdtool => {
+          64 => {
+            'ALL' => 'rrdtool.i686',
+            'centos6' => 'rrdtool.i686',
+            'centos5' => 'rrdtool.i386',
+            'redhat6' => 'rrdtool.i686',
+            'redhat5' => 'rrdtool.i386'
+            }
+    },
     ambari-log4j => {
       64 => ['ambari-log4j']
     } 
@@ -393,6 +403,7 @@ class hdp::params()
      suse => 'htpasswd2'} 
 
     }
+    
 
     $alt_package_names = 
 {
@@ -511,6 +522,18 @@ class hdp::params()
     rrdtool-python => {
       64 => {'ALL' =>'python-rrdtool.x86_64'}
     },
+
+    # The 32bit version of package rrdtool is removed on centos 5/6 to prevent conflict ( BUG-2408)
+    rrdtool => {
+      64 => {
+        'ALL' => 'rrdtool.i686',
+        'centos6' => 'rrdtool.i686',
+        'centos5' => 'rrdtool.i386',
+        'redhat6' => 'rrdtool.i686',
+        'redhat5' => 'rrdtool.i386'
+        }
+    },
+
     ambari-log4j => {
       64 => {'ALL' =>'ambari-log4j'}
     },
@@ -531,7 +554,14 @@ class hdp::params()
     redhat5 => '/etc/yum.repos.d'
   }
 
-  $rrd_py_path = '/var/www/cgi-bin'
+  $rrd_py_path =
+  {
+    suse => '/srv/www/cgi-bin',
+    centos6 => '/var/www/cgi-bin',
+    centos5 => '/var/www/cgi-bin',
+    redhat6 => '/var/www/cgi-bin',
+    redhat5 => '/var/www/cgi-bin'
+  }
 
 
 

+ 2 - 2
ambari-agent/src/main/python/ambari_agent/AmbariConfig.py

@@ -28,8 +28,8 @@ content = """
 
 [server]
 hostname=localhost
-url_port=4080
-secured_url_port=8443
+url_port=8440
+secured_url_port=8441
 
 [agent]
 prefix=/tmp/ambari-agent

+ 15 - 0
ambari-agent/src/main/python/ambari_agent/Grep.py

@@ -1,3 +1,18 @@
+# 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 re
 
 class Grep:

+ 16 - 6
ambari-agent/src/main/python/ambari_agent/Hardware.py

@@ -60,8 +60,8 @@ class Hardware:
                      'mountpoint' : mountpoint,
                      'type': type,
                      'device' : device }
-
-        mounts.append(mountinfo)
+        if os.access(mountpoint, os.W_OK):
+          mounts.append(mountinfo)
         pass
       pass
     return mounts
@@ -104,8 +104,18 @@ class Hardware:
           value = keyValue[1].strip()
           """Convert to KB"""
           parts = value.split()
-          #TODO need better parsing for detecting KB/GB
-          mem_in_kb = long(float(parts[0]) * 1024 * 1024);
+          if len(parts) == 2:
+            mem_size = parts[1].upper()
+            if mem_size in ["GB", "G"]:
+              mem_in_kb = long(float(parts[0]) * 1024 * 1024)
+            elif mem_size in ["MB", "M"]:
+              mem_in_kb = long(float(parts[0]) * 1024)
+            elif mem_size in ["KB", "K"]:
+              mem_in_kb = long(float(parts[0]))
+            else:
+              mem_in_kb = long(float(parts[0]) / 1024)
+          else:
+            mem_in_kb = long(float(parts[0]) / 1024)
           retDict[strippedKey] = mem_in_kb
           pass
         else:
@@ -122,7 +132,7 @@ class Hardware:
       pass
     
     logger.info("Facter info : \n" + pprint.pformat(retDict))
-    return retDict
+    return retDict  
   
   def facterInfo(self):   
     facterHome = AmbariConfig.config.get("puppet", "facter_home")
@@ -154,7 +164,7 @@ class Hardware:
         facterInfo = infoDict
         pass
       else:
-        pass
+        logger.error("Facter home at " + facterHome + " does not exist")
     except:
       logger.info("Traceback " + traceback.format_exc())
       pass

+ 20 - 2
ambari-agent/src/main/python/ambari_agent/NetUtil.py

@@ -1,3 +1,19 @@
+# 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 httplib import HTTPS
 from urlparse import urlparse
 import time
@@ -34,8 +50,10 @@ class NetUtil:
       status = response.status    
       logger.info("DEBUG: Calling url received " + str(status))
       
-      if status == 200: return True
-      else: return False
+      if status == 200: 
+        return True
+      else: 
+        return False
     except Exception, e:
       logger.info("Failed to connect to " + str(url) + " due to " + str(e))
       return False

+ 60 - 0
ambari-agent/src/main/python/ambari_agent/machine.py

@@ -0,0 +1,60 @@
+#!/usr/bin/env python2.6
+
+'''
+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 sys
+import subprocess
+
+# please keep compatible with Python 2.4 or greater
+def doExec(key, command, preLF=False):
+  try:
+    osStat = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+    out, err = osStat.communicate()
+    if 0 != osStat.returncode or 0 == len(out.strip()):
+      print "%s: UNAVAILABLE" % (key)
+    else:
+      if (preLF):
+        print "%s: ok\n %s" % (key, out.strip())
+      else:
+        print "%s: ok %s" % (key, out.strip())
+  except:
+    print "%s: UNAVAILABLE" % (key)
+  
+def main(argv=None):
+  doExec('hostname', ["hostname", "-f"])
+  doExec('ip', ["hostname", "-i"])
+  doExec('cpu', ["sh", "-c", "cat /proc/cpuinfo | grep 'model name' | awk -F': ' '{ print $2; }'"])
+  doExec('memory', ["sh", "-c", "cat /proc/meminfo | grep MemTotal | awk -F': ' '{ print $2/1024/1024 \" GB\"; }'"])
+  doExec('disks', ["df", "-h"], True)
+  doExec('os', ["sh", "-c", "cat /etc/issue.net | head -1"])
+  doExec('iptables', ["iptables", "-vnL"], True)
+  doExec('selinux', ["sh", "-c", "cat /etc/selinux/config | grep ^SELINUX"])
+
+  for REQ in (["yum", "rpm", "openssl", "curl", "wget", "net-snmp", "net-snmp-utils", "ntpd"]):
+   doExec(REQ, ["rpm", "-qa", REQ])
+
+  for OPT in (["ruby", "puppet", "nagios", "ganglia", "passenger", "hadoop"]):
+   doExec(OPT, ["rpm", "-qa", OPT])
+
+  doExec("yum_repos", ["sh", "-c", "yum -C repolist enabled | egrep \"(AMBARI|HDP)\""], True)
+  # for SUSE-based agents
+  doExec("zypper_repos", ["sh", "-c", "zypper repos | egrep \"(AMBARI|HDP)\""], True)
+
+if __name__ == '__main__':
+  main(sys.argv)

+ 2 - 2
ambari-agent/src/main/python/ambari_agent/main.py

@@ -126,8 +126,8 @@ def main():
   # Check for ambari configuration file.
   try:
     config = AmbariConfig.config
-    if os.path.exists('/etc/ambari-agent/ambari-agent.ini'):
-      config.read('/etc/ambari-agent/ambari-agent.ini')
+    if os.path.exists('/etc/ambari-agent/conf/ambari-agent.ini'):
+      config.read('/etc/ambari-agent/conf/ambari-agent.ini')
       AmbariConfig.setConfig(config)
     else:
       raise Exception("No config found, use default")

+ 20 - 9
ambari-agent/src/main/python/ambari_agent/manifestGenerator.py

@@ -34,7 +34,7 @@ non_global_configuration_types = ["hdfs-site", "core-site",
                              "hadoop-policy", "mapred-site", 
                              "capacity-scheduler", "hbase-site",
                              "hbase-policy", "hive-site", "oozie-site", 
-                             "templeton-site", "hdfs-exclude-file"]
+                             "webhcat-site", "hdfs-exclude-file"]
 
 #read static imports from file and write them to manifest
 def writeImports(outputFile, modulesdir, inputFileName='imports.txt'):
@@ -112,7 +112,7 @@ def generateManifest(parsedJson, fileName, modulesdir, ambariconfig):
   #writeHostAttributes(manifest, hostAttributes)
 
   #writing task definitions 
-  writeTasks(manifest, roles, ambariconfig)
+  writeTasks(manifest, roles, ambariconfig, clusterHostInfo, hostname)
      
   manifest.close()
     
@@ -130,6 +130,9 @@ def readDict(file, separator='='):
 
   #write nodes
 def writeNodes(outputFile, clusterHostInfo):
+  if clusterHostInfo.has_key('zookeeper_hosts'):
+    clusterHostInfo['zookeeper_hosts'] = sorted(clusterHostInfo['zookeeper_hosts'])
+  
   for node in clusterHostInfo.iterkeys():
     outputFile.write('$' + node + '= [')
     coma = ''
@@ -203,7 +206,8 @@ def writeNonGlobalConfigurations(outputFile, xmlConfigs):
   outputFile.write('\n}\n')
 
 #write node tasks
-def writeTasks(outputFile, roles, ambariconfig):
+def writeTasks(outputFile, roles, ambariconfig, clusterHostInfo=None, 
+               hostname="localhost"):
   #reading dictionaries
   rolestoclass = "rolesToClass.dict"
   if ambariconfig.has_option('puppet','roles_to_class'):
@@ -228,13 +232,17 @@ def writeTasks(outputFile, roles, ambariconfig):
 
   outputFile.write('class {\'hdp\': stage => ' + str(stageNum) + '}\n')
   stageNum = stageNum + 1
-
+  # Need to hack for zookeeper since we need 
+  zk_hosts = []
   for role in roles :
     rolename = role['role']
     command = role['cmd']
     taskParams = role['roleParams']
     if (rolename == 'ZOOKEEPER_SERVER'):
-      taskParams['myid'] = str(get_mac())
+      zk_hosts = clusterHostInfo['zookeeper_hosts']
+      # Sort the list in lexicographical order
+      taskParams['myid'] = str(sorted(zk_hosts).index(hostname) + 1)
+    
     taskParamsNormalized = normalizeTaskParams(taskParams)
     taskParamsPostfix = ''
     
@@ -245,11 +253,14 @@ def writeTasks(outputFile, roles, ambariconfig):
    
     if command in serviceStates:
       serviceState = serviceStates[command] 
-      outputFile.write('class {\'' + className + '\':' + ' stage => ' + str(stageNum) + 
-                     ', service_state => ' + serviceState + taskParamsPostfix + '}\n')
+      outputFile.write('class {\'' + className + '\':' +
+                        ' stage => ' + str(stageNum) + 
+                     ', service_state => ' + serviceState 
+                     + taskParamsPostfix + '}\n')
     else:
-      outputFile.write('class {\'' + className + '\':' + ' stage => ' + str(stageNum) + 
-                     taskParamsPostfix + '}\n')
+      outputFile.write('class {\'' + className + '\':' + 
+                       ' stage => ' + str(stageNum) + 
+                       taskParamsPostfix + '}\n')
 
     stageNum = stageNum + 1
   outputFile.write('}\n')

+ 16 - 2
ambari-agent/src/main/python/ambari_agent/rolesToClass.dict

@@ -1,3 +1,18 @@
+# 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.
+
 NAMENODE = hdp-hadoop::namenode
 DATANODE = hdp-hadoop::datanode
 SECONDARY_NAMENODE = hdp-hadoop::snamenode
@@ -15,8 +30,7 @@ SQOOP = hdp-sqoop
 OOZIE_SERVER = hdp-oozie::server
 OOZIE_CLIENT = hdp-oozie::client
 HIVE_CLIENT = hdp-hive::client
-HCATALOG_CLIENT = hdp-hcat
-HCATALOG_SERVER = hdp-hcat::server
+HCAT = hdp-hcat
 HIVE_SERVER = hdp-hive::server
 HIVE_METASTORE = hdp-hive::metastore
 MYSQL_SERVER = hdp-mysql::server

+ 16 - 0
ambari-agent/src/main/python/ambari_agent/security.py

@@ -1,5 +1,21 @@
 #!/usr/bin/env python2.6
 
+# 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 httplib
 import urllib2
 from urllib2 import Request

+ 15 - 0
ambari-agent/src/main/python/ambari_agent/serviceStates.dict

@@ -1,3 +1,18 @@
+# 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.
+
 START = running
 INSTALL = installed_and_configured
 STOP = stopped

+ 15 - 0
ambari-agent/src/main/python/ambari_agent/servicesToPidNames.dict

@@ -1,3 +1,18 @@
+# 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.
+
 NAMENODE=hadoop-hdfs-namenode.pid
 SECONDARY_NAMENODE=hadoop-hdfs-secondarynamenode.pid
 DATANODE=hadoop-hdfs-datanode.pid

+ 1 - 1
ambari-agent/src/test/python/TestActionQueue.py

@@ -43,7 +43,7 @@ class TestActionQueue(TestCase):
   def test_command_in_progress(self):
     config = AmbariConfig().getConfig()
     tmpfile = tempfile.gettempdir()
-    config.set('puppet', 'puppetmodules', tmpfile)
+    config.set('agent', 'prefix', tmpfile)
     actionQueue = ActionQueue(config)
     actionQueue.IDLE_SLEEP_TIME = 0.01
     executor_started_event = threading.Event()

+ 1 - 1
ambari-agent/src/test/python/TestNetUtil.py

@@ -59,7 +59,7 @@ class TestNetUtil(TestCase):
     self.assertEquals(netutil.checkURL('http://192.168.253.177'), False, "Not reachable IP")
     if hasattr(socket, 'setdefaulttimeout'):
       # Set the default timeout on sockets
-      socket.setdefaulttimeout(10)
+      socket.setdefaulttimeout(20)
     self.assertEquals(netutil.checkURL('http://www.iana.org/domains/example/'), True, "Good url - HTTP code 200")
     self.assertEquals(netutil.checkURL('https://www.iana.org/domains/example/'), True, "Good HTTPS url - HTTP code 200")
 

+ 2 - 2
ambari-project/pom.xml

@@ -17,11 +17,11 @@
   <parent>
     <groupId>org.apache.ambari</groupId>
     <artifactId>ambari</artifactId>
-    <version>1.0.3-SNAPSHOT</version>
+    <version>1.2.0-SNAPSHOT</version>
   </parent>
   <groupId>org.apache.ambari</groupId>
   <artifactId>ambari-project</artifactId>
-  <version>1.0.3-SNAPSHOT</version>
+  <version>1.2.0-SNAPSHOT</version>
   <description>Apache Ambari Project POM</description>
   <name>Apache Ambari Project POM</name>
   <packaging>pom</packaging>

+ 15 - 0
ambari-server/conf/unix/ambari-env.sh

@@ -1 +1,16 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
 AMBARI_PASSHPHRASE="DEV"

+ 17 - 0
ambari-server/conf/unix/ambari.properties

@@ -1,3 +1,20 @@
+# Copyright 2011 The Apache Software Foundation
+#
+# 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.
 security.server.keys_dir = /var/lib/ambari-server/keys
 resources.dir = /var/lib/ambari-server/resources
 jdk.url=http://public-repo-1.hortonworks.com/ARTIFACTS/jdk-6u31-linux-x64.bin

+ 2 - 2
ambari-server/derby.log

@@ -1,6 +1,6 @@
 ----------------------------------------------------------------
-Mon Dec 10 15:32:34 PST 2012:
-Booting Derby version The Apache Software Foundation - Apache Derby - 10.9.1.0 - (1344872): instance a816c00e-013b-8729-b0b0-000003feb140 
+Mon Jan 07 23:30:20 PST 2013:
+Booting Derby version The Apache Software Foundation - Apache Derby - 10.9.1.0 - (1344872): instance a816c00e-013c-1911-2686-000003d87098 
 on database directory memory:/Users/mahadev/workspace/ambari-workspace/ambari-git/ambari-server/myDB  with class loader sun.misc.Launcher$AppClassLoader@27a8c4e7 
 Loaded from file:/Users/mahadev/.m2/repository/org/apache/derby/derby/10.9.1.0/derby-10.9.1.0.jar
 java.vendor=Apple Inc.

+ 13 - 0
ambari-server/exclude.xml

@@ -1,4 +1,17 @@
 <?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed 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. See accompanying LICENSE file.
+-->
 
 <FindBugsFilter>
 

+ 26 - 20
ambari-server/pom.xml

@@ -1,19 +1,22 @@
 <?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. -->
+<!--
+  Licensed 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. See accompanying LICENSE file.
+-->
 <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/maven-v4_0_0.xsd">
   <parent>
     <groupId>org.apache.ambari</groupId>
     <artifactId>ambari-project</artifactId>
-    <version>1.0.3-SNAPSHOT</version>
+    <version>1.2.0-SNAPSHOT</version>
     <relativePath>../ambari-project</relativePath>
   </parent>
   <modelVersion>4.0.0</modelVersion>
@@ -21,7 +24,7 @@
   <artifactId>ambari-server</artifactId>
   <packaging>jar</packaging>
   <name>Ambari Server</name>
-  <version>1.0.3-SNAPSHOT</version>
+  <version>1.2.0-SNAPSHOT</version>
   <description>Ambari Server</description>
   <properties>
     <python.ver>python &gt;= 2.6</python.ver>
@@ -48,7 +51,18 @@
       <plugin>
         <groupId>org.apache.rat</groupId>
         <artifactId>apache-rat-plugin</artifactId>
+          <version>0.8</version>
         <configuration>
+          <numUnapprovedLicenses>8</numUnapprovedLicenses>
+          <excludes>
+              <exclude>pass.txt</exclude>
+              <exclude>derby.log</exclude>
+              <exclude>src/test/resources/users.ldif</exclude>
+              <exclude>src/main/resources/ca.config</exclude>
+              <exclude>src/main/resources/db/serial</exclude>
+              <exclude>src/main/resources/db/index.txt</exclude>
+              <exclude>conf/unix/ca.config</exclude>
+          </excludes>
           <includes>
             <include>pom.xml</include>
           </includes>
@@ -272,10 +286,6 @@
       <groupId>commons-io</groupId>
       <artifactId>commons-io</artifactId>
     </dependency>
-    <dependency>
-      <groupId>com.google.inject</groupId>
-      <artifactId>guice</artifactId>
-    </dependency>
     <dependency>
       <groupId>com.google.inject.extensions</groupId>
       <artifactId>guice-assistedinject</artifactId>
@@ -340,10 +350,6 @@
       <groupId>org.eclipse.persistence</groupId>
       <artifactId>eclipselink</artifactId>
     </dependency>
-    <dependency>
-      <groupId>postgresql</groupId>
-      <artifactId>postgresql</artifactId>
-    </dependency>
     <dependency>
       <groupId>org.mockito</groupId>
       <artifactId>mockito-core</artifactId>

+ 20 - 1
ambari-server/sbin/ambari-server

@@ -2,6 +2,22 @@
 # description: ambari-server daemon
 # processname: ambari-server
 
+# 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.
+
 # /etc/init.d/ambari-server
 
 export PATH=/usr/lib/ambari-server/*:$PATH
@@ -59,7 +75,10 @@ case "$1" in
         ;;
   setup)
         echo -e "Run postgresql initdb"
-        /sbin/service postgresql initdb
+        initdb_res=`/sbin/service postgresql initdb`
+        if [ "0" == "$?" ]; then
+          echo -e "${initdb_res}"
+        fi
         echo -e "Run postgresql start"
         /sbin/service postgresql start
         echo -e "Setup ambari-server"

+ 0 - 18
ambari-server/src/examples/spec.json

@@ -1,21 +1,3 @@
-/**
- * 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.
- */
-
 {
   "stack":{
     "comment":"Stack Definition defines where the artifacts need to be fetched from.""name":"hdp-1.0.1",

+ 17 - 0
ambari-server/src/main/conf/ambari.properties

@@ -1 +1,18 @@
+# Copyright 2011 The Apache Software Foundation
+#
+# 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.
 metadata.path=src/main/resources/stacks

+ 34 - 0
ambari-server/src/main/java/org/apache/ambari/server/DuplicateResourceException.java

@@ -0,0 +1,34 @@
+/**
+ * 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 org.apache.ambari.server;
+
+/**
+ * Thrown when an attempt is made to create an already existing resource.
+ */
+public class DuplicateResourceException extends AmbariException {
+
+  /**
+   * Constructor.
+   *
+   * @param message  message
+   */
+  public DuplicateResourceException(String message) {
+    super(message);
+  }
+}

+ 4 - 0
ambari-server/src/main/java/org/apache/ambari/server/HostNotFoundException.java

@@ -24,4 +24,8 @@ public class HostNotFoundException extends ObjectNotFoundException {
   public HostNotFoundException(String hostname) {
     super("Host not found, hostname=" + hostname);
   }
+
+  public HostNotFoundException(String clusterName, String hostname) {
+    super("Host not found, cluster=" + clusterName + ", hostname=" + hostname);
+  }
 }

+ 44 - 0
ambari-server/src/main/java/org/apache/ambari/server/ParentObjectNotFoundException.java

@@ -0,0 +1,44 @@
+/**
+ * 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 org.apache.ambari.server;
+
+/**
+ * Indicates that a parent of a resource doesn't exist.
+ */
+public class ParentObjectNotFoundException extends AmbariException {
+
+  /**
+   * Constructor.
+   *
+   * @param msg    message
+   * @param cause  the root cause
+   */
+  public ParentObjectNotFoundException(String msg, ObjectNotFoundException cause) {
+    super(msg + ".  " + cause.getMessage(), cause);
+  }
+
+  /**
+   * Constructor.
+   *
+   * @param message message
+   */
+  public ParentObjectNotFoundException(String message) {
+    super(message);
+  }
+}

+ 1 - 0
ambari-server/src/main/java/org/apache/ambari/server/actionmanager/Stage.java

@@ -199,6 +199,7 @@ public class Stage {
     }
 
     if (execCmdList.contains(wrapper)) {
+      //todo: proper exception
       throw new RuntimeException(
           "Setting the execution command second time for same stage: stage="
               + this.getActionId() + ", host=" + host + ", role=" + role);

+ 48 - 56
ambari-server/src/main/java/org/apache/ambari/server/api/handlers/BaseManagementHandler.java

@@ -19,16 +19,19 @@
 package org.apache.ambari.server.api.handlers;
 
 import org.apache.ambari.server.api.resources.ResourceInstance;
-import org.apache.ambari.server.api.resources.ResourceInstanceFactory;
-import org.apache.ambari.server.api.resources.ResourceInstanceFactoryImpl;
-import org.apache.ambari.server.api.services.PersistenceManager;
 import org.apache.ambari.server.api.services.Request;
 import org.apache.ambari.server.api.services.Result;
 import org.apache.ambari.server.api.services.ResultImpl;
+import org.apache.ambari.server.api.services.persistence.PersistenceManager;
+import org.apache.ambari.server.api.services.persistence.PersistenceManagerImpl;
 import org.apache.ambari.server.api.util.TreeNode;
-import org.apache.ambari.server.controller.spi.*;
+import org.apache.ambari.server.controller.spi.ClusterController;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.controller.spi.RequestStatus;
+import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.controller.utilities.ClusterControllerHelper;
-import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import java.util.Map;
 import java.util.Set;
@@ -36,8 +39,22 @@ import java.util.Set;
 /**
  * Base handler for operations that persist state to the back-end.
  */
-public class BaseManagementHandler implements RequestHandler {
-  @Override
+public abstract class BaseManagementHandler implements RequestHandler {
+
+  /**
+   * Logger instance.
+   */
+  protected final static Logger LOG =
+      LoggerFactory.getLogger(BaseManagementHandler.class);
+
+  /**
+   * PersistenceManager implementation.
+   */
+  PersistenceManager m_pm = new PersistenceManagerImpl(getClusterController());
+
+  protected BaseManagementHandler() {
+  }
+
   public Result handleRequest(Request request) {
     ResourceInstance resource = request.getResource();
     Predicate queryPredicate = request.getQueryPredicate();
@@ -45,71 +62,46 @@ public class BaseManagementHandler implements RequestHandler {
       resource.getQuery().setUserPredicate(queryPredicate);
     }
 
-    return handleRequest(request.getPersistenceManager(), resource,
-        request.getHttpBodyProperties(), request.getURI());
+    return handleRequest(resource, request.getHttpBodyProperties());
   }
 
-  protected Result handleRequest(PersistenceManager pm, ResourceInstance resource,
-                                 Set<Map<String, Object>> setProperties, String uri) {
-
-    return createResult(uri, pm.persist(resource, setProperties));
+  protected Result handleRequest(ResourceInstance resource, Set<Map<String, Object>> setProperties) {
+    return persist(resource, setProperties);
   }
 
-  private Result createResult(String uri, RequestStatus requestStatus) {
-    boolean isSynchronous = requestStatus.getStatus() == RequestStatus.Status.Complete;
+  protected Result createResult(RequestStatus requestStatus) {
 
-    Result result = new ResultImpl(isSynchronous);
-    TreeNode<Resource> tree = result.getResultTree();
-
-    Set<Resource> setResources = requestStatus.getAssociatedResources();
-    TreeNode<Resource> resourcesNode = null;
-    if (! setResources.isEmpty()) {
-      resourcesNode = tree.addChild(null, "resources");
-    }
-    int count = 1;
-    for (Resource resource : setResources) {
-      //todo: provide a more meaningful node name
-      resourcesNode.addChild(resource, resource.getType() + ":" + count++);
-    }
+    boolean            isSynchronous = requestStatus.getStatus() == RequestStatus.Status.Complete;
+    Result             result        = new ResultImpl(isSynchronous);
+    TreeNode<Resource> tree          = result.getResultTree();
 
     if (! isSynchronous) {
-      Resource requestResource = requestStatus.getRequestResource();
-      TreeNode<Resource> r = tree.addChild(requestResource, "request");
-      r.setProperty("href", buildRequestHref(uri, requestStatus));
+      tree.addChild(requestStatus.getRequestResource(), "request");
     }
 
-    return result;
-  }
-
-  private String buildRequestHref(String uri, RequestStatus requestStatus) {
-    StringBuilder sb = new StringBuilder();
-    String[] toks = uri.split("/");
+    //todo: currently always empty
+    Set<Resource> setResources = requestStatus.getAssociatedResources();
+    if (! setResources.isEmpty()) {
+      TreeNode<Resource> resourcesNode = tree.addChild(null, "resources");
 
-    for (int i = 0; i < toks.length; ++i) {
-      String s = toks[i];
-      sb.append(s).append('/');
-      if ("clusters".equals(s)) {
-        sb.append(toks[i + 1]).append('/');
-        break;
+      int count = 1;
+      for (Resource resource : setResources) {
+        //todo: provide a more meaningful node name
+        resourcesNode.addChild(resource, resource.getType() + ":" + count++);
       }
     }
 
-    //todo: shouldn't know property name
-    Object requestId = requestStatus.getRequestResource().getPropertyValue(
-        PropertyHelper.getPropertyId("Requests", "id"));
-
-    sb.append("requests/").append(requestId);
-
-    return sb.toString();
-  }
-
-  //todo: How to get reference to factory?
-  protected ResourceInstanceFactory getResourceFactory() {
-    return new ResourceInstanceFactoryImpl();
+    return result;
   }
 
-  //todo: how to get cluster controller?
+  //todo: controller should be injected
   protected ClusterController getClusterController() {
     return ClusterControllerHelper.getClusterController();
   }
+
+  protected PersistenceManager getPersistenceManager() {
+    return m_pm;
+  }
+
+  protected abstract Result persist(ResourceInstance r, Set<Map<String, Object>> properties);
 }

+ 42 - 4
ambari-server/src/main/java/org/apache/ambari/server/api/handlers/CreateHandler.java

@@ -18,18 +18,56 @@
 
 package org.apache.ambari.server.api.handlers;
 
+import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.*;
+import org.apache.ambari.server.api.services.ResultStatus;
+import org.apache.ambari.server.controller.spi.*;
+
+import java.util.Map;
+import java.util.Set;
 
 
 /**
  * Responsible for create requests.
  */
 public class CreateHandler extends BaseManagementHandler {
+
   @Override
-  public Result handleRequest(Request request) {
-    Result result = super.handleRequest(request);
-    //todo: what to return from create?
-    //todo: create specific exceptions
+  protected Result persist(ResourceInstance r, Set<Map<String, Object>> properties) {
+    Result result;
+    try {
+      RequestStatus status = getPersistenceManager().create(r, properties);
+
+      result = createResult(status);
+
+      if (result.isSynchronous()) {
+        result.setResultStatus(new ResultStatus(ResultStatus.STATUS.CREATED));
+      } else {
+        result.setResultStatus(new ResultStatus(ResultStatus.STATUS.ACCEPTED));
+      }
+
+    } catch (UnsupportedPropertyException e) {
+      result = new ResultImpl(new ResultStatus(ResultStatus.STATUS.BAD_REQUEST, e.getMessage()));
+    } catch (NoSuchParentResourceException e) {
+      //todo: is this the correct status code?
+      result = new ResultImpl(new ResultStatus(ResultStatus.STATUS.NOT_FOUND, e.getMessage()));
+    } catch (SystemException e) {
+      if (LOG.isErrorEnabled()) {
+        LOG.error("Caught a system exception while attempting to create a resource", e.getMessage());
+      }
+      result = new ResultImpl(new ResultStatus(ResultStatus.STATUS.SERVER_ERROR, e.getMessage()));
+    } catch (ResourceAlreadyExistsException e) {
+      result = new ResultImpl(new ResultStatus(ResultStatus.STATUS.CONFLICT, e.getMessage()));
+    } catch(IllegalArgumentException e) {
+      result = new ResultImpl(new ResultStatus(ResultStatus.STATUS.BAD_REQUEST, e.getMessage()));
+    } catch (RuntimeException e) {
+      if (LOG.isErrorEnabled()) {
+        LOG.error("Caught a runtime exception while attempting to create a resource", e);
+      }
+      //result = new ResultImpl(new ResultStatus(ResultStatus.STATUS.SERVER_ERROR, e.getMessage()));
+      throw e;
+    }
+
     return result;
   }
 }

+ 38 - 5
ambari-server/src/main/java/org/apache/ambari/server/api/handlers/DeleteHandler.java

@@ -18,16 +18,49 @@
 
 package org.apache.ambari.server.api.handlers;
 
-import org.apache.ambari.server.api.services.Request;
+import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.services.ResultStatus;
 import org.apache.ambari.server.api.services.Result;
+import org.apache.ambari.server.api.services.ResultImpl;
+import org.apache.ambari.server.controller.spi.*;
+
+import java.util.Map;
+import java.util.Set;
 
 /**
  * Responsible for delete requests.
  */
-public class DeleteHandler extends BaseManagementHandler {
+public class DeleteHandler extends BaseManagementHandler implements RequestHandler {
+
   @Override
-  public Result handleRequest(Request request) {
-    //todo: delete specific return information, delete specific exceptions
-    return super.handleRequest(request);
+  protected Result persist(ResourceInstance r, Set<Map<String, Object>> properties) {
+    Result result;
+      try {
+        RequestStatus status = getPersistenceManager().delete(r, properties);
+        result = createResult(status);
+
+        if (result.isSynchronous()) {
+          result.setResultStatus(new ResultStatus(ResultStatus.STATUS.OK));
+        } else {
+          result.setResultStatus(new ResultStatus(ResultStatus.STATUS.ACCEPTED));
+        }
+      } catch (SystemException e) {
+        result = new ResultImpl(new ResultStatus(ResultStatus.STATUS.SERVER_ERROR, e));
+      } catch (NoSuchParentResourceException e) {
+        result = new ResultImpl(new ResultStatus(ResultStatus.STATUS.NOT_FOUND, e));
+      } catch (NoSuchResourceException e) {
+        if (r.isCollectionResource()) {
+          //todo: The query didn't match any resource so no resources were updated.
+          //todo: 200 may be ok but we need to return a collection
+          //todo: of resources that were updated.
+          result = new ResultImpl(new ResultStatus(ResultStatus.STATUS.OK, e));
+        } else {
+          result = new ResultImpl(new ResultStatus(ResultStatus.STATUS.NOT_FOUND, e));
+        }
+      } catch (UnsupportedPropertyException e) {
+        result = new ResultImpl(new ResultStatus(ResultStatus.STATUS.BAD_REQUEST, e));
+      }
+
+    return result;
   }
 }

+ 51 - 16
ambari-server/src/main/java/org/apache/ambari/server/api/handlers/QueryCreateHandler.java

@@ -19,14 +19,15 @@
 
 package org.apache.ambari.server.api.handlers;
 
-import org.apache.ambari.server.AmbariException;
-import org.apache.ambari.server.api.query.Query;
 import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.api.resources.ResourceInstanceFactory;
+import org.apache.ambari.server.api.resources.ResourceInstanceFactoryImpl;
 import org.apache.ambari.server.api.services.Request;
+import org.apache.ambari.server.api.services.ResultStatus;
 import org.apache.ambari.server.api.services.Result;
+import org.apache.ambari.server.api.services.ResultImpl;
 import org.apache.ambari.server.api.util.TreeNode;
-import org.apache.ambari.server.controller.spi.ClusterController;
-import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.*;
 
 import java.util.*;
 
@@ -35,28 +36,27 @@ import java.util.*;
  */
 public class QueryCreateHandler extends BaseManagementHandler {
 
+  private RequestHandler m_readHandler = new ReadHandler();
+
   @Override
   public Result handleRequest(Request request) {
-    ResourceInstance resource = request.getResource();
-    Query query = resource.getQuery();
-    query.setUserPredicate(request.getQueryPredicate());
+    Result queryResult = getReadHandler().handleRequest(request);
+    if (queryResult.getStatus().isErrorState() ||
+        queryResult.getResultTree().getChildren().isEmpty()) {
 
-    Result queryResult;
-    try {
-      //todo: only care about primary key
-      queryResult = query.execute();
-    } catch (AmbariException e) {
-      //TODO: exceptions
-      throw new RuntimeException("An exception occurred executing the query portion of the request: " + e, e);
+      //return the query result if result has error state or contains no resources
+      //todo: For case where no resources are returned, will return 200 ok.
+      //todo: What is the appropriate status code?
+      return queryResult;
     }
 
+    ResourceInstance resource = request.getResource();
     Resource.Type createType = getCreateType(request.getHttpBody(), resource);
     Set<Map<String, Object>> setProperties = buildCreateSet(request, queryResult, createType);
     ResourceInstance createResource = getResourceFactory().createResource(
         createType, request.getResource().getIds());
 
-    return super.handleRequest(request.getPersistenceManager(),
-        createResource, setProperties, request.getURI());
+    return super.handleRequest(createResource, setProperties);
   }
 
   private Set<Map<String, Object>> buildCreateSet(Request request, Result queryResult, Resource.Type createType) {
@@ -91,4 +91,39 @@ public class QueryCreateHandler extends BaseManagementHandler {
     ResourceInstance res =  resource.getSubResources().get(requestBody.substring(startIdx, endIdx));
     return res == null ? null : res.getResourceDefinition().getType();
   }
+
+  @Override
+  protected Result persist(ResourceInstance r, Set<Map<String, Object>> properties) {
+    Result result;
+    try {
+      RequestStatus status = getPersistenceManager().create(r, properties);
+
+      result = createResult(status);
+
+      if (result.isSynchronous()) {
+        result.setResultStatus(new ResultStatus(ResultStatus.STATUS.CREATED));
+      } else {
+        result.setResultStatus(new ResultStatus(ResultStatus.STATUS.ACCEPTED));
+      }
+
+    } catch (UnsupportedPropertyException e) {
+      result = new ResultImpl(new ResultStatus(ResultStatus.STATUS.BAD_REQUEST, e));
+    } catch (ResourceAlreadyExistsException e) {
+      result = new ResultImpl(new ResultStatus(ResultStatus.STATUS.CONFLICT, e));
+    } catch (NoSuchParentResourceException e) {
+      result = new ResultImpl(new ResultStatus(ResultStatus.STATUS.NOT_FOUND, e));
+    } catch (SystemException e) {
+      result = new ResultImpl(new ResultStatus(ResultStatus.STATUS.SERVER_ERROR, e));
+    }
+
+    return result;
+  }
+
+  protected ResourceInstanceFactory getResourceFactory() {
+    return new ResourceInstanceFactoryImpl();
+  }
+
+  protected RequestHandler getReadHandler() {
+    return m_readHandler;
+  }
 }

+ 53 - 12
ambari-server/src/main/java/org/apache/ambari/server/api/handlers/ReadHandler.java

@@ -19,11 +19,14 @@
 package org.apache.ambari.server.api.handlers;
 
 import org.apache.ambari.server.api.services.Request;
+import org.apache.ambari.server.api.services.ResultImpl;
+import org.apache.ambari.server.api.services.ResultStatus;
 import org.apache.ambari.server.api.services.Result;
 import org.apache.ambari.server.api.query.Query;
-import org.apache.ambari.server.AmbariException;
-import org.apache.ambari.server.controller.spi.TemporalInfo;
+import org.apache.ambari.server.controller.spi.*;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import java.util.Map;
 
@@ -32,24 +35,62 @@ import java.util.Map;
  */
 public class ReadHandler implements RequestHandler {
 
+  /**
+   * Logger instance.
+   */
+  private final static Logger LOG =
+      LoggerFactory.getLogger(ReadHandler.class);
+
   @Override
   public Result handleRequest(Request request) {
     Query query = request.getResource().getQuery();
 
+    try {
+      addFieldsToQuery(request, query);
+    } catch (IllegalArgumentException e) {
+      return new ResultImpl(new ResultStatus(ResultStatus.STATUS.BAD_REQUEST, e.getMessage()));
+    }
+
+    query.setUserPredicate(request.getQueryPredicate());
+    Result result;
+    try {
+      result = query.execute();
+      result.setResultStatus(new ResultStatus(ResultStatus.STATUS.OK));
+    } catch (SystemException e) {
+      result = new ResultImpl(new ResultStatus(ResultStatus.STATUS.SERVER_ERROR, e));
+    } catch (NoSuchParentResourceException e) {
+      result = new ResultImpl(new ResultStatus(ResultStatus.STATUS.NOT_FOUND, e.getMessage()));
+    } catch (UnsupportedPropertyException e) {
+      result = new ResultImpl(new ResultStatus(ResultStatus.STATUS.BAD_REQUEST, e.getMessage()));
+    } catch (NoSuchResourceException e) {
+      if (request.getQueryPredicate() == null) {
+        // no predicate specified, resource requested by id
+        result = new ResultImpl(new ResultStatus(ResultStatus.STATUS.NOT_FOUND, e.getMessage()));
+      } else {
+        // resource(s) requested using predicate
+        result = new ResultImpl(new ResultStatus(ResultStatus.STATUS.OK, e));
+        result.getResultTree().setProperty("isCollection", "true");
+      }
+    } catch (IllegalArgumentException e) {
+      result = new ResultImpl(new ResultStatus(ResultStatus.STATUS.BAD_REQUEST,
+          "Invalid Request: " + e.getMessage()));
+    } catch (RuntimeException e) {
+      if (LOG.isErrorEnabled()) {
+        LOG.error("Caught a runtime exception executing a query", e);
+      }
+      //result = new ResultImpl(new ResultStatus(ResultStatus.STATUS.SERVER_ERROR, e));
+      throw e;
+    }
+    return result;
+  }
+
+  private void addFieldsToQuery(Request request, Query query) throws IllegalArgumentException {
     //Partial response
     for (Map.Entry<String, TemporalInfo> entry : request.getFields().entrySet()) {
       // Iterate over map and add props/temporalInfo
       String propertyId = entry.getKey();
-      query.addProperty(PropertyHelper.getPropertyCategory(propertyId), PropertyHelper.getPropertyName(propertyId), entry.getValue());
-    }
-
-   query.setUserPredicate(request.getQueryPredicate());
-
-    try {
-      return query.execute();
-    } catch (AmbariException e) {
-      //TODO: exceptions
-      throw new RuntimeException("An exception occurred processing the request: " + e, e);
+      query.addProperty(PropertyHelper.getPropertyCategory(propertyId),
+          PropertyHelper.getPropertyName(propertyId), entry.getValue());
     }
   }
 }

+ 1 - 0
ambari-server/src/main/java/org/apache/ambari/server/api/handlers/RequestHandler.java

@@ -18,6 +18,7 @@
 
 package org.apache.ambari.server.api.handlers;
 
+import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.api.services.Request;
 import org.apache.ambari.server.api.services.Result;
 

+ 35 - 4
ambari-server/src/main/java/org/apache/ambari/server/api/handlers/UpdateHandler.java

@@ -18,18 +18,49 @@
 
 package org.apache.ambari.server.api.handlers;
 
+import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.services.*;
+import org.apache.ambari.server.controller.spi.*;
+
+import java.util.Map;
+import java.util.Set;
 
 
 /**
  * Responsible for update requests.
  */
 public class UpdateHandler extends BaseManagementHandler {
+
   @Override
-  public Result handleRequest(Request request) {
-    Result result = super.handleRequest(request);
-    //todo: what to return from update?
-    //todo: update specific exceptions
+  protected Result persist(ResourceInstance r, Set<Map<String, Object>> properties) {
+    Result result;
+    try {
+      RequestStatus status = getPersistenceManager().update(r, properties);
+
+      result = createResult(status);
+      if (result.isSynchronous()) {
+        result.setResultStatus(new ResultStatus(ResultStatus.STATUS.OK));
+      } else {
+        result.setResultStatus(new ResultStatus(ResultStatus.STATUS.ACCEPTED));
+      }
+
+    } catch (UnsupportedPropertyException e) {
+      result = new ResultImpl(new ResultStatus(ResultStatus.STATUS.BAD_REQUEST, e));
+    } catch (NoSuchParentResourceException e) {
+      result = new ResultImpl(new ResultStatus(ResultStatus.STATUS.NOT_FOUND, e));
+    } catch (NoSuchResourceException e) {
+      if (r.isCollectionResource()) {
+        //todo: what is the correct status code here.  The query didn't match any resource
+        //todo: so no resource were updated.  200 may be ok but we would need to return a collection
+        //todo: of resources that were updated.
+        result = new ResultImpl(new ResultStatus(ResultStatus.STATUS.OK, e));
+      } else {
+        result = new ResultImpl(new ResultStatus(ResultStatus.STATUS.NOT_FOUND, e));
+      }
+    } catch (SystemException e) {
+      result = new ResultImpl(new ResultStatus(ResultStatus.STATUS.SERVER_ERROR, e));
+    }
+
     return result;
   }
 }

+ 11 - 7
ambari-server/src/main/java/org/apache/ambari/server/api/query/Query.java

@@ -19,9 +19,7 @@
 package org.apache.ambari.server.api.query;
 
 import org.apache.ambari.server.api.services.Result;
-import org.apache.ambari.server.AmbariException;
-import org.apache.ambari.server.controller.spi.Predicate;
-import org.apache.ambari.server.controller.spi.TemporalInfo;
+import org.apache.ambari.server.controller.spi.*;
 
 import java.util.Map;
 import java.util.Set;
@@ -36,9 +34,9 @@ public interface Query {
    * Add a property to the query.
    * This is the select portion of the query.
    *
-   * @param group    the group name that contains the property
-   * @param property the property name
-   * @param temporalInfo
+   * @param group         the group name that contains the property
+   * @param property      the property name
+   * @param temporalInfo  temporal information for the property
    */
   public void addProperty(String group, String property, TemporalInfo temporalInfo);
 
@@ -64,8 +62,14 @@ public interface Query {
    * Execute the query.
    *
    * @return the result of the query.
+   *
+   * @throws UnsupportedPropertyException if the query or query predicate contains invalid non-existent properties
+   * @throws SystemException an internal error occurred
+   * @throws NoSuchResourceException the query didn't match any resources
+   * @throws NoSuchParentResourceException a specified parent resource doesn't exist
    */
-  public Result execute() throws AmbariException;
+  public Result execute()
+      throws UnsupportedPropertyException, SystemException, NoSuchResourceException, NoSuchParentResourceException;
 
   /**
    * Return the predicate used to identify the associated resource.  This includes the primary key and

+ 16 - 15
ambari-server/src/main/java/org/apache/ambari/server/api/query/QueryImpl.java

@@ -23,7 +23,6 @@ import org.apache.ambari.server.api.services.ResultImpl;
 import org.apache.ambari.server.api.util.TreeNodeImpl;
 import org.apache.ambari.server.controller.utilities.ClusterControllerHelper;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
-import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.controller.predicate.AndPredicate;
 import org.apache.ambari.server.controller.predicate.BasePredicate;
 import org.apache.ambari.server.controller.predicate.EqualsPredicate;
@@ -119,9 +118,10 @@ public class QueryImpl implements Query {
       // not a local category/property
       boolean success = addPropertyToSubResource(category, property, temporalInfo);
       if (!success) {
-        //TODO
-        throw new RuntimeException("Attempted to add invalid property to resource.  Resource=" +
-            m_resource.getResourceDefinition().getType() + ", Property: Category=" + category + " Field=" + property);
+        //TODO.  Remove when handled by back end
+        String propString = category == null ? property : property == null ? category : category + '/' + property;
+        throw new IllegalArgumentException("An invalid resource property was requested.  Resource: " +
+            m_resource.getResourceDefinition().getType() + ", Property: " + propString);
       }
     }
   }
@@ -132,9 +132,10 @@ public class QueryImpl implements Query {
   }
 
   @Override
-  public Result execute() throws AmbariException {
-    Result result = createResult();
+  public Result execute()
+      throws UnsupportedPropertyException, SystemException, NoSuchResourceException, NoSuchParentResourceException {
 
+    Result result = createResult();
     Resource.Type resourceType = m_resource.getResourceDefinition().getType();
     if (m_resource.getIds().get(resourceType) == null) {
       addCollectionProperties(resourceType);
@@ -147,14 +148,8 @@ public class QueryImpl implements Query {
     }
 
     Predicate predicate = createPredicate(m_resource);
-    Iterable<Resource> iterResource = null;
-
-    try {
-      iterResource = getClusterController().getResources(
-          resourceType, createRequest(), predicate);
-    } catch (UnsupportedPropertyException e) {
-      // TODO ...
-    }
+    Iterable<Resource> iterResource = getClusterController().getResources(
+        resourceType, createRequest(), predicate);
 
     TreeNode<Resource> tree = result.getResultTree();
     int count = 1;
@@ -235,7 +230,13 @@ public class QueryImpl implements Query {
   }
 
   private boolean addCategory(String category, String name, TemporalInfo temporalInfo) {
-    name = category != null ? category + '/' + name : name;
+    if (category != null) {
+      if (name != null && ! name.isEmpty()) {
+        name = category + '/' + name;
+      } else  {
+        name = category;
+      }
+    }
     TreeNode<Set<String>> node = m_treeAllProperties.getChild(name);
     if (node == null) {
       return false;

+ 32 - 0
ambari-server/src/main/java/org/apache/ambari/server/api/resources/RequestResourceDefinition.java

@@ -19,9 +19,12 @@
 package org.apache.ambari.server.api.resources;
 
 
+import org.apache.ambari.server.api.services.Request;
+import org.apache.ambari.server.api.util.TreeNode;
 import org.apache.ambari.server.controller.spi.Resource;
 
 import java.util.Collections;
+import java.util.List;
 import java.util.Set;
 
 
@@ -51,4 +54,33 @@ public class RequestResourceDefinition extends BaseResourceDefinition {
   public Set<SubResourceDefinition> getSubResourceDefinitions() {
       return Collections.singleton(new SubResourceDefinition(Resource.Type.Task));
   }
+
+  @Override
+  public List<PostProcessor> getPostProcessors() {
+    return Collections.<PostProcessor>singletonList(new RequestHrefPostProcessor());
+  }
+
+  private class RequestHrefPostProcessor implements PostProcessor {
+    @Override
+    public void process(Request request, TreeNode<Resource> resultNode, String href) {
+      StringBuilder sb = new StringBuilder();
+      String[] toks = href.split("/");
+
+      for (int i = 0; i < toks.length; ++i) {
+        String s = toks[i];
+        sb.append(s).append('/');
+        if ("clusters".equals(s)) {
+          sb.append(toks[i + 1]).append('/');
+          break;
+        }
+      }
+
+      Object requestId = resultNode.getObject().getPropertyValue(getClusterController().
+          getSchema(Resource.Type.Request).getKeyPropertyId(Resource.Type.Request));
+
+      sb.append("requests/").append(requestId);
+
+      resultNode.setProperty("href", sb.toString());
+    }
+  }
 }

+ 7 - 0
ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstance.java

@@ -67,4 +67,11 @@ public interface ResourceInstance {
    * @return all sub-resource instances
    */
   public Map<String, ResourceInstance> getSubResources();
+
+  /**
+   * Determine if resource is a collection resource.
+   *
+   * @return true if the resource is a collection resource; false otherwise
+   */
+  public boolean isCollectionResource();
 }

+ 5 - 0
ambari-server/src/main/java/org/apache/ambari/server/api/resources/ResourceInstanceImpl.java

@@ -126,6 +126,11 @@ public class ResourceInstanceImpl implements ResourceInstance {
     return m_mapSubResources;
   }
 
+  @Override
+  public boolean isCollectionResource() {
+    return getIds().get(getResourceDefinition().getType()) == null;
+  }
+
   @Override
   public boolean equals(Object o) {
     if (this == o) return true;

+ 241 - 0
ambari-server/src/main/java/org/apache/ambari/server/api/services/BaseRequest.java

@@ -0,0 +1,241 @@
+/**
+ * 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 org.apache.ambari.server.api.services;
+
+import org.apache.ambari.server.api.resources.*;
+import org.apache.ambari.server.api.services.parsers.JsonPropertyParser;
+import org.apache.ambari.server.api.services.parsers.RequestBodyParser;
+import org.apache.ambari.server.api.services.serializers.JsonSerializer;
+import org.apache.ambari.server.api.services.serializers.ResultSerializer;
+import org.apache.ambari.server.controller.internal.TemporalInfoImpl;
+import org.apache.ambari.server.controller.predicate.*;
+import org.apache.ambari.server.controller.spi.Predicate;
+import org.apache.ambari.server.controller.spi.TemporalInfo;
+
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.UriInfo;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Request implementation.
+ */
+public abstract class BaseRequest implements Request {
+
+  /**
+   * URI information
+   */
+  private UriInfo m_uriInfo;
+
+  /**
+   * Http headers
+   */
+  private HttpHeaders m_headers;
+
+  /**
+   * Http Body
+   */
+  private String m_body;
+
+
+  /**
+   * Predicate operators.
+   */
+  private Pattern m_pattern = Pattern.compile("!=|>=|<=|=|>|<");
+
+  /**
+   * Associated resource definition
+   */
+  private ResourceInstance m_resource;
+
+
+  /**
+   * Constructor.
+   *
+   * @param headers      http headers
+   * @param body         http body
+   * @param uriInfo      uri information
+   * @param resource     associated resource definition
+   */
+  public BaseRequest(HttpHeaders headers, String body, UriInfo uriInfo, ResourceInstance resource) {
+
+    m_headers  = headers;
+    m_body     = body;
+    m_uriInfo  = uriInfo;
+    m_resource = resource;
+  }
+
+  @Override
+  public ResourceInstance getResource() {
+    return m_resource;
+  }
+
+  @Override
+  public String getURI() {
+    try {
+      return URLDecoder.decode(m_uriInfo.getRequestUri().toASCIIString(), "UTF-8");
+    } catch (UnsupportedEncodingException e) {
+      throw new RuntimeException("Unable to decode URI: " + e, e);
+    }
+  }
+
+  @Override
+  public int getAPIVersion() {
+    return 0;
+  }
+
+  @Override
+  public Predicate getQueryPredicate() {
+    //todo: parse during init
+    //not using getQueryParameters because it assumes '=' operator
+    String uri = getURI();
+    int qsBegin = uri.indexOf("?");
+
+    if (qsBegin == -1) return null;
+
+    String[] tokens = uri.substring(qsBegin + 1).split("&");
+
+    Set<BasePredicate> setPredicates = new HashSet<BasePredicate>();
+    for (String outerToken : tokens) {
+      if (outerToken != null &&  !outerToken.startsWith("fields")) {
+        setPredicates.add(outerToken.contains("|") ?
+            handleOrPredicate(outerToken) : createPredicate(outerToken));
+      }
+    }
+
+    if (setPredicates.size() == 1) {
+      return setPredicates.iterator().next();
+    } else if (setPredicates.size() > 1) {
+      return new AndPredicate(setPredicates.toArray(new BasePredicate[setPredicates.size()]));
+    } else {
+      return null;
+    }
+  }
+
+  @Override
+  public Map<String, TemporalInfo> getFields() {
+    Map<String, TemporalInfo> mapProperties;
+    String partialResponseFields = m_uriInfo.getQueryParameters().getFirst("fields");
+    if (partialResponseFields == null) {
+      mapProperties = Collections.emptyMap();
+    } else {
+      Set<String> setMatches = new HashSet<String>();
+      // Pattern basically splits a string using ',' as the deliminator unless ',' is between '[' and ']'.
+      // Actually, captures char sequences between ',' and all chars between '[' and ']' including ','.
+      Pattern re = Pattern.compile("[^,\\[]*?\\[[^\\]]*?\\]|[^,]+");
+      Matcher m = re.matcher(partialResponseFields);
+      while (m.find()){
+        for (int groupIdx = 0; groupIdx < m.groupCount() + 1; groupIdx++) {
+          setMatches.add(m.group(groupIdx));
+        }
+      }
+
+      mapProperties = new HashMap<String, TemporalInfo>(setMatches.size());
+      for (String field : setMatches) {
+        TemporalInfo temporalInfo = null;
+        if (field.contains("[")) {
+          String[] temporalData = field.substring(field.indexOf('[') + 1,
+              field.indexOf(']')).split(",");
+          field = field.substring(0, field.indexOf('['));
+          long start = Long.parseLong(temporalData[0].trim());
+          long end   = -1;
+          long step  = -1;
+          if (temporalData.length >= 2) {
+            end = Long.parseLong(temporalData[1].trim());
+            if (temporalData.length == 3) {
+              step = Long.parseLong(temporalData[2].trim());
+            }
+          }
+          temporalInfo = new TemporalInfoImpl(start, end, step);
+        }
+        mapProperties.put(field, temporalInfo);
+      }
+    }
+
+    return mapProperties;
+  }
+
+  @Override
+  public Map<String, List<String>> getHttpHeaders() {
+    return m_headers.getRequestHeaders();
+  }
+
+  @Override
+  public String getHttpBody() {
+    return m_body;
+  }
+
+  @Override
+  public Set<Map<String, Object>> getHttpBodyProperties() {
+    return getHttpBodyParser().parse(getHttpBody());
+  }
+
+  @Override
+  public ResultSerializer getResultSerializer() {
+    return new JsonSerializer();
+  }
+
+  @Override
+  public ResultPostProcessor getResultPostProcessor() {
+    return new ResultPostProcessorImpl(this);
+  }
+
+  private BasePredicate createPredicate(String token) {
+
+    Matcher m = m_pattern.matcher(token);
+    m.find();
+
+    String propertyId = token.substring(0, m.start());
+    String     value      = token.substring(m.end());
+    String     operator   = m.group();
+
+    if (operator.equals("=")) {
+      return new EqualsPredicate<String>(propertyId, value);
+    } else if (operator.equals("!=")) {
+      return new NotPredicate(new EqualsPredicate<String>(propertyId, value));
+    } else if (operator.equals("<")) {
+      return new LessPredicate<String>(propertyId, value);
+    } else if (operator.equals(">"))  {
+      return new GreaterPredicate<String>(propertyId, value);
+    } else if (operator.equals("<=")) {
+      return new LessEqualsPredicate<String>(propertyId, value);
+    } else if (operator.equals(">=")) {
+      return new GreaterEqualsPredicate<String>(propertyId, value);
+    } else {
+      throw new RuntimeException("Unknown operator provided in predicate: " + operator);
+    }
+  }
+
+  private BasePredicate handleOrPredicate(String predicate) {
+    Set<BasePredicate> setPredicates = new HashSet<BasePredicate>();
+    String[] tokens = predicate.split("\\|");
+    for (String tok : tokens) {
+      setPredicates.add(createPredicate(tok));
+    }
+
+    return new OrPredicate(setPredicates.toArray(new BasePredicate[setPredicates.size()]));
+  }
+
+  protected RequestBodyParser getHttpBodyParser() {
+    return new JsonPropertyParser();
+  }
+}

+ 29 - 19
ambari-server/src/main/java/org/apache/ambari/server/api/services/BaseService.java

@@ -18,9 +18,8 @@
 
 package org.apache.ambari.server.api.services;
 
-import org.apache.ambari.server.api.handlers.DelegatingRequestHandler;
 import org.apache.ambari.server.api.handlers.RequestHandler;
-import org.apache.ambari.server.api.resources.ResourceDefinition;
+import org.apache.ambari.server.api.handlers.RequestHandlerFactory;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.api.resources.ResourceInstanceFactory;
 import org.apache.ambari.server.api.resources.ResourceInstanceFactoryImpl;
@@ -37,8 +36,16 @@ import java.util.Map;
  */
 public abstract class BaseService {
 
+  /**
+   * Factory for creating resource instances.
+   */
   private ResourceInstanceFactory m_resourceFactory = new ResourceInstanceFactoryImpl();
 
+  /**
+   * Factory for creating request handlers.
+   */
+  private RequestHandlerFactory m_handlerFactory = new RequestHandlerFactory();
+
   /**
    * All requests are funneled through this method so that common logic can be executed.
    * This consists of creating a {@link Request} instance, invoking the correct {@link RequestHandler} and
@@ -55,12 +62,16 @@ public abstract class BaseService {
   protected Response handleRequest(HttpHeaders headers, String body, UriInfo uriInfo, Request.Type requestType,
                                    ResourceInstance resource) {
 
-    Request request = getRequestFactory().createRequest(headers, body, uriInfo, requestType, resource);
-    Result result = getRequestHandler().handleRequest(request);
+    Request request = getRequestFactory().createRequest(
+        headers, body, uriInfo, requestType, resource);
+
+    Result result = getRequestHandler(request.getRequestType()).handleRequest(request);
+    if (! result.getStatus().isErrorState()) {
+      request.getResultPostProcessor().process(result);
+    }
 
-    return getResponseFactory().createResponse(requestType,
-        request.getResultSerializer().serialize(result, uriInfo),
-        result.isSynchronous());
+    return Response.status(result.getStatus().getStatusCode()).entity(
+        request.getResultSerializer().serialize(result)).build();
   }
 
   /**
@@ -73,25 +84,24 @@ public abstract class BaseService {
   }
 
   /**
-   * Obtain the factory from which to create Response instances.
+   * Obtain the appropriate RequestHandler for the request.
    *
-   * @return the Response factory
+   * @param requestType  the request type
+   *
+   * @return the request handler to invoke
    */
-  ResponseFactory getResponseFactory() {
-    return new ResponseFactory();
+  RequestHandler getRequestHandler(Request.Type requestType) {
+    return m_handlerFactory.getRequestHandler(requestType);
   }
 
   /**
-   * Obtain the appropriate RequestHandler for the request.  At this time all requests are funneled through
-   * a delegating request handler which will ultimately delegate the request to the appropriate concrete
-   * request handler.
+   * Create a resource instance.
    *
-   * @return the request handler to invoke
+   * @param type    the resource type
+   * @param mapIds  all primary and foreign key properties and values
+   *
+   * @return a newly created resource instance
    */
-  RequestHandler getRequestHandler() {
-    return new DelegatingRequestHandler();
-  }
-
   ResourceInstance createResource(Resource.Type type, Map<Resource.Type, String> mapIds) {
     return m_resourceFactory.createResource(type, mapIds);
   }

+ 47 - 0
ambari-server/src/main/java/org/apache/ambari/server/api/services/DeleteRequest.java

@@ -0,0 +1,47 @@
+/**
+ * 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 org.apache.ambari.server.api.services;
+
+import org.apache.ambari.server.api.resources.ResourceInstance;
+
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.UriInfo;
+
+/**
+ * A DELETE request.
+ */
+public class DeleteRequest extends BaseRequest {
+  /**
+   * Constructor.
+   *
+   * @param headers     http headers
+   * @param body        http body
+   * @param uriInfo     uri information
+   * @param resource    associated resource definition
+   */
+  public DeleteRequest(HttpHeaders headers, String body, UriInfo uriInfo, ResourceInstance resource) {
+    super(headers, body, uriInfo, resource);
+  }
+
+  @Override
+  public Type getRequestType() {
+    return Type.DELETE;
+  }
+
+}

+ 46 - 0
ambari-server/src/main/java/org/apache/ambari/server/api/services/GetRequest.java

@@ -0,0 +1,46 @@
+/**
+ * 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 org.apache.ambari.server.api.services;
+
+import org.apache.ambari.server.api.resources.ResourceInstance;
+
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.UriInfo;
+
+/**
+ * A GET request.
+ */
+public class GetRequest extends BaseRequest {
+  /**
+   * Constructor.
+   *
+   * @param headers     http headers
+   * @param body        http body
+   * @param uriInfo     uri information
+   * @param resource    associated resource definition
+   */
+  public GetRequest(HttpHeaders headers, String body, UriInfo uriInfo, ResourceInstance resource) {
+    super(headers, body, uriInfo, resource);
+  }
+
+  @Override
+  public Type getRequestType() {
+    return Type.GET;
+  }
+}

+ 47 - 0
ambari-server/src/main/java/org/apache/ambari/server/api/services/PostRequest.java

@@ -0,0 +1,47 @@
+/**
+ * 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 org.apache.ambari.server.api.services;
+
+import org.apache.ambari.server.api.resources.ResourceInstance;
+
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.UriInfo;
+
+/**
+ * A POST request.
+ */
+public class PostRequest extends BaseRequest {
+  /**
+   * Constructor.
+   *
+   * @param headers     http headers
+   * @param body        http body
+   * @param uriInfo     uri information
+   * @param resource    associated resource definition
+   */
+  public PostRequest(HttpHeaders headers, String body, UriInfo uriInfo, ResourceInstance resource) {
+    super(headers, body, uriInfo, resource);
+  }
+
+  @Override
+  public Type getRequestType() {
+    return Type.POST;
+  }
+
+}

+ 47 - 0
ambari-server/src/main/java/org/apache/ambari/server/api/services/PutRequest.java

@@ -0,0 +1,47 @@
+/**
+ * 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 org.apache.ambari.server.api.services;
+
+import org.apache.ambari.server.api.resources.ResourceInstance;
+
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.UriInfo;
+
+/**
+ * A PUT request.
+ */
+public class PutRequest extends BaseRequest {
+  /**
+   * Constructor.
+   *
+   * @param headers     http headers
+   * @param body        http body
+   * @param uriInfo     uri information
+   * @param resource    associated resource definition
+   */
+  public PutRequest(HttpHeaders headers, String body, UriInfo uriInfo, ResourceInstance resource) {
+    super(headers, body, uriInfo, resource);
+  }
+
+  @Override
+  public Type getRequestType() {
+    return Type.PUT;
+  }
+
+}

+ 59 - 0
ambari-server/src/main/java/org/apache/ambari/server/api/services/QueryPostRequest.java

@@ -0,0 +1,59 @@
+/**
+ * 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 org.apache.ambari.server.api.services;
+
+import org.apache.ambari.server.api.resources.ResourceInstance;
+
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.UriInfo;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Request for creating sub-resources of instances based on a query.
+ */
+public class QueryPostRequest extends PostRequest {
+  /**
+   * Constructor.
+   *
+   * @param headers      http headers
+   * @param body         http body
+   * @param uriInfo      uri information
+   * @param resource     associated resource instance
+   */
+  public QueryPostRequest(HttpHeaders headers, String body, UriInfo uriInfo, ResourceInstance resource) {
+    super(headers, body, uriInfo, resource);
+  }
+
+  @Override
+  public Set<Map<String, Object>> getHttpBodyProperties() {
+    String httpBody = getHttpBody();
+    //strip array name
+    int startIdx = httpBody.indexOf("[");
+    int endIdx = httpBody.lastIndexOf("]");
+
+    return getHttpBodyParser().parse(httpBody.substring(startIdx, endIdx + 1));
+  }
+
+  @Override
+  public Type getRequestType() {
+    return Type.QUERY_POST;
+  }
+}

+ 0 - 7
ambari-server/src/main/java/org/apache/ambari/server/api/services/Request.java

@@ -125,11 +125,4 @@ public interface Request {
    * @return a set of maps containing the properties contained in the http body
    */
   public Set<Map<String, Object>> getHttpBodyProperties();
-
-  /**
-   * Obtain the appropriate persistence manager.
-   *
-   * @return the appropriate persistence manager
-   */
-  public PersistenceManager getPersistenceManager();
 }

+ 14 - 9
ambari-server/src/main/java/org/apache/ambari/server/api/services/RequestFactory.java

@@ -39,15 +39,20 @@ public class RequestFactory {
    */
   public Request createRequest(HttpHeaders headers, String body, UriInfo uriInfo, Request.Type requestType,
                                ResourceInstance resource) {
-
-    if (requestType == Request.Type.POST &&
-        ! uriInfo.getQueryParameters().isEmpty() &&
-        body != null) {
-
-      return new QueryCreateRequest(headers, body, uriInfo, requestType, resource);
-
-    } else {
-      return new RequestImpl(headers, body, uriInfo, requestType, resource);
+    switch (requestType) {
+      case GET:
+        return new GetRequest(headers, body, uriInfo, resource);
+      case PUT:
+        return new PutRequest(headers, body, uriInfo, resource);
+      case DELETE:
+        return new DeleteRequest(headers, body, uriInfo, resource);
+      case POST:
+        return (uriInfo.getQueryParameters().isEmpty() || body == null) ?
+            new PostRequest(headers, body, uriInfo, resource) :
+            new QueryPostRequest(headers, body, uriInfo, resource);
+      default:
+        throw new IllegalArgumentException("Invalid request type: " + requestType);
     }
   }
+
 }

+ 40 - 2
ambari-server/src/main/java/org/apache/ambari/server/api/services/Result.java

@@ -26,18 +26,56 @@ import org.apache.ambari.server.api.util.TreeNode;
  * Represents a result from a request handler invocation.
  */
 public interface Result {
+
+  public static enum STATUS { OK(200, "OK", false), CREATED(201, "Created", false), ACCEPTED(202, "Accepted", false),
+    CONFLICT(409, "Resource Conflict", true), NOT_FOUND(404, "Not Found", true), BAD_REQUEST(400, "Bad Request", true),
+    UNAUTHORIZED(401, "Unauthorized", true), FORBIDDEN(403, "Forbidden", true),
+    SERVER_ERROR(500, "Internal Server Error", true);
+
+    private int    m_code;
+    private String m_desc;
+    private boolean m_isErrorState;
+
+    private STATUS(int code, String description, boolean isErrorState) {
+      m_code = code;
+      m_desc = description;
+      m_isErrorState = isErrorState;
+    }
+
+    public int getStatus() {
+      return m_code;
+    }
+
+    public String getDescription() {
+      return m_desc;
+    }
+
+    public boolean isErrorState() {
+      return m_isErrorState;
+    }
+
+    @Override
+    public String toString() {
+      return getDescription();
+    }
+  };
+
   /**
-   * the results of the request invocation as a Tree structure.
+   * Obtain the results of the request invocation as a Tree structure.
    *
    * @return the results of the request a a Tree structure
    */
   public TreeNode<Resource> getResultTree();
 
   /**
-   * Determine whether the request was handle synchronously.
+   * Determine whether the request was handled synchronously.
    * If the request is synchronous, all work was completed prior to returning.
    *
    * @return true if the request was synchronous, false if it was asynchronous
    */
   public boolean isSynchronous();
+
+  public ResultStatus getStatus();
+
+  public void setResultStatus(ResultStatus status);
 }

+ 30 - 0
ambari-server/src/main/java/org/apache/ambari/server/api/services/ResultImpl.java

@@ -34,15 +34,35 @@ public class ResultImpl implements Result {
    */
   private boolean m_synchronous;
 
+  /**
+   * Result status.
+   */
+  private ResultStatus m_status;
+
   /**
    * Tree structure which holds the results
    */
   private TreeNode<Resource> m_tree = new TreeNodeImpl<Resource>(null, null, null);
 
+
+  /**
+   * Constructor.
+   *
+   * @param synchronous true if request was handled synchronously, false otherwise
+   */
   public ResultImpl(boolean synchronous) {
     m_synchronous = synchronous;
   }
 
+  /**
+   * Constructor.
+   *
+   * @param status  result status
+   */
+  public ResultImpl(ResultStatus status) {
+    m_status = status;
+  }
+
   @Override
   public TreeNode<Resource> getResultTree() {
     return m_tree;
@@ -52,5 +72,15 @@ public class ResultImpl implements Result {
   public boolean isSynchronous() {
     return m_synchronous;
   }
+
+  @Override
+  public ResultStatus getStatus() {
+    return m_status;
+  }
+
+  @Override
+  public void setResultStatus(ResultStatus status) {
+    m_status = status;
+  }
 }
 

+ 5 - 0
ambari-server/src/main/java/org/apache/ambari/server/api/services/ResultPostProcessorImpl.java

@@ -18,6 +18,7 @@
 
 package org.apache.ambari.server.api.services;
 
+import org.apache.ambari.server.api.resources.RequestResourceDefinition;
 import org.apache.ambari.server.api.resources.ResourceDefinition;
 import org.apache.ambari.server.api.resources.ResourceInstance;
 import org.apache.ambari.server.controller.spi.Resource;
@@ -99,6 +100,7 @@ public class ResultPostProcessorImpl implements ResultPostProcessor {
    * @param resource the root resource
    */
   private void registerResourceProcessors(ResourceInstance resource) {
+    //todo: reconsider registration mechanism
     Resource.Type type = resource.getResourceDefinition().getType();
     List<ResourceDefinition.PostProcessor> listProcessors = m_mapPostProcessors.get(type);
     if (listProcessors == null) {
@@ -113,6 +115,9 @@ public class ResultPostProcessorImpl implements ResultPostProcessor {
         registerResourceProcessors(child);
       }
     }
+
+    // always add Request post processors since they may be returned but will not be a child
+    m_mapPostProcessors.put(Resource.Type.Request, new RequestResourceDefinition().getPostProcessors());
   }
 
 }

+ 176 - 0
ambari-server/src/main/java/org/apache/ambari/server/api/services/ResultStatus.java

@@ -0,0 +1,176 @@
+/**
+ * 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 org.apache.ambari.server.api.services;
+
+/**
+ * Result status information.
+ */
+public class ResultStatus {
+
+  /**
+   * STATUS enum. Maps a status to a status code.
+   */
+  public static enum STATUS { OK(200, "OK", false), CREATED(201, "Created", false), ACCEPTED(202, "Accepted", false),
+    CONFLICT(409, "Resource Conflict", true), NOT_FOUND(404, "Not Found", true), BAD_REQUEST(400, "Bad Request", true),
+    UNAUTHORIZED(401, "Unauthorized", true), FORBIDDEN(403, "Forbidden", true),
+    SERVER_ERROR(500, "Internal Server Error", true);
+
+    /**
+     * Status code
+     */
+    private int m_code;
+
+    /**
+     * Description
+     */
+    private String m_desc;
+
+    /**
+     * whether this is an error state
+     */
+    private boolean m_isErrorState;
+
+    /**
+     * Constructor.
+     *
+     * @param code         status code
+     * @param description  description
+     * @param isErrorState whether this is an error state
+     */
+    private STATUS(int code, String description, boolean isErrorState) {
+      m_code = code;
+      m_desc = description;
+      m_isErrorState = isErrorState;
+    }
+
+    /**
+     * Obtain the status code.
+     * This is an http response code.
+     *
+     * @return  the status code
+     */
+    public int getStatus() {
+      return m_code;
+    }
+
+    /**
+     * Obtain a brief description.
+     *
+     * @return the description
+     */
+    public String getDescription() {
+      return m_desc;
+    }
+
+    /**
+     * Whether this status is an error state
+     *
+     * @return true if this is an error state; false otherwise
+     */
+    public boolean isErrorState() {
+      return m_isErrorState;
+    }
+
+    @Override
+    public String toString() {
+      return getDescription();
+    }
+  }
+
+  /**
+   * Status instance
+   */
+  private STATUS m_status;
+
+  /**
+   * Result status message
+   */
+  private String m_msg;
+
+  /**
+   * Constructor.
+   *
+   * @param status result status
+   * @param msg    result msg.  Usually used in case of an error.
+   */
+  public ResultStatus(STATUS status, String msg) {
+    m_status       = status;
+    m_msg          = msg;
+  }
+
+  /**
+   * Constructor.
+   *
+   * @param status  result status
+   */
+  public ResultStatus(STATUS status) {
+    m_status = status;
+  }
+
+  /**
+   * Constructor.
+   *
+   * @param status  result status
+   * @param e       result exception
+   */
+  public ResultStatus(STATUS status, Exception e) {
+    m_status = status;
+    m_msg = e.toString();
+  }
+
+  /**
+   * Obtain the result status.
+   * The result status contains a status code and a description of the status.
+   *
+   * @return  the result status
+   */
+  public STATUS getStatus() {
+    return m_status;
+  }
+
+  /**
+   * Obtain the status code.
+   * This is a shortcut to obtaining the status code from the associated result status.
+   *
+   * @return the status code
+   */
+  public int getStatusCode() {
+    return m_status.getStatus();
+  }
+
+  /**
+   * Determine whether the status is an error state.
+   * This is a shortcut to getting this information from the associated result status.
+   *
+   * @return true if the status is a result state; false otherwise
+   */
+  public boolean isErrorState() {
+    return m_status.isErrorState();
+  }
+
+  /**
+   * Obtain the result message.
+   * This message is usually used when an exception occurred.
+   *
+   * @return the result message
+   */
+  public String getMessage() {
+    return m_msg;
+  }
+}

+ 45 - 0
ambari-server/src/main/java/org/apache/ambari/server/api/services/persistence/PersistenceManager.java

@@ -0,0 +1,45 @@
+/**
+ * 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 org.apache.ambari.server.api.services.persistence;
+
+import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.controller.spi.*;
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Persistence manager which is responsible for persisting a resource state to the back end.
+ * This includes create, update and delete operations.
+ */
+public interface PersistenceManager {
+
+  public RequestStatus create(ResourceInstance resource, Set<Map<String, Object>> setProperties)
+      throws UnsupportedPropertyException,
+             ResourceAlreadyExistsException,
+             NoSuchParentResourceException,
+             SystemException;
+
+  public RequestStatus update(ResourceInstance resource, Set<Map<String, Object>> setProperties)
+      throws UnsupportedPropertyException, SystemException, NoSuchParentResourceException, NoSuchResourceException;
+
+
+  public RequestStatus delete(ResourceInstance resource, Set<Map<String, Object>> setProperties)
+      throws UnsupportedPropertyException, SystemException, NoSuchParentResourceException, NoSuchResourceException;
+}

+ 94 - 0
ambari-server/src/main/java/org/apache/ambari/server/api/services/persistence/PersistenceManagerImpl.java

@@ -0,0 +1,94 @@
+/**
+ * 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 org.apache.ambari.server.api.services.persistence;
+
+import org.apache.ambari.server.api.resources.ResourceInstance;
+import org.apache.ambari.server.controller.spi.*;
+import org.apache.ambari.server.controller.utilities.PropertyHelper;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Persistence Manager implementation.
+ */
+public class PersistenceManagerImpl implements PersistenceManager {
+
+  /**
+   * Cluster Controller reference.
+   */
+  private ClusterController m_controller;
+
+  /**
+   * Constructor.
+   *
+   * @param controller  the cluster controller
+   */
+  public PersistenceManagerImpl(ClusterController controller) {
+    m_controller = controller;
+  }
+
+  @Override
+  public RequestStatus create(ResourceInstance resource, Set<Map<String, Object>> setProperties)
+      throws UnsupportedPropertyException,
+             SystemException,
+             ResourceAlreadyExistsException,
+             NoSuchParentResourceException {
+
+    Map<Resource.Type, String> mapResourceIds = resource.getIds();
+    Resource.Type type = resource.getResourceDefinition().getType();
+    Schema schema = m_controller.getSchema(type);
+
+    if (setProperties.size() == 0) {
+      setProperties.add(new HashMap<String, Object>());
+    }
+
+    for (Map<String, Object> mapProperties : setProperties) {
+      for (Map.Entry<Resource.Type, String> entry : mapResourceIds.entrySet()) {
+        String property = schema.getKeyPropertyId(entry.getKey());
+        if (! mapProperties.containsKey(property)) {
+          mapProperties.put(property, entry.getValue());
+        }
+      }
+    }
+    return m_controller.createResources(type, createControllerRequest(setProperties));
+  }
+
+  @Override
+  public RequestStatus update(ResourceInstance resource, Set<Map<String, Object>> setProperties)
+      throws UnsupportedPropertyException, SystemException, NoSuchParentResourceException, NoSuchResourceException {
+
+    return m_controller.updateResources(resource.getResourceDefinition().getType(),
+        createControllerRequest(setProperties), resource.getQuery().getPredicate());
+  }
+
+  @Override
+  public RequestStatus delete(ResourceInstance resource, Set<Map<String, Object>> setProperties)
+      throws UnsupportedPropertyException, SystemException, NoSuchParentResourceException, NoSuchResourceException {
+    //todo: need to account for multiple resources and user predicate
+    return m_controller.deleteResources(resource.getResourceDefinition().getType(),
+        resource.getQuery().getPredicate());
+
+  }
+
+  protected Request createControllerRequest(Set<Map<String, Object>> setProperties) {
+    return PropertyHelper.getCreateRequest(setProperties);
+  }
+}

+ 35 - 9
ambari-server/src/main/java/org/apache/ambari/server/api/services/serializers/JsonSerializer.java

@@ -18,19 +18,17 @@
 
 package org.apache.ambari.server.api.services.serializers;
 
+import org.apache.ambari.server.api.services.ResultStatus;
 import org.apache.ambari.server.api.services.Result;
 import org.apache.ambari.server.controller.spi.Resource;
 import org.apache.ambari.server.api.util.TreeNode;
 import org.codehaus.jackson.JsonFactory;
-import org.codehaus.jackson.JsonGenerationException;
 import org.codehaus.jackson.JsonGenerator;
 import org.codehaus.jackson.map.ObjectMapper;
 import org.codehaus.jackson.util.DefaultPrettyPrinter;
 
-import javax.ws.rs.core.UriInfo;
 import java.io.*;
 import java.nio.charset.Charset;
-import java.util.Collection;
 import java.util.Map;
 
 /**
@@ -53,25 +51,53 @@ public class JsonSerializer implements ResultSerializer {
 
 
   @Override
-  public Object serialize(Result result, UriInfo uriInfo) {
+  public Object serialize(Result result) {
     try {
-      ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
-      m_generator = createJsonGenerator(bytesOut);
+      ByteArrayOutputStream bytesOut = init();
 
-      DefaultPrettyPrinter p = new DefaultPrettyPrinter();
-      p.indentArraysWith(new DefaultPrettyPrinter.Lf2SpacesIndenter());
-      m_generator.setPrettyPrinter(p);
+      if (result.getStatus().isErrorState()) {
+        return serializeError(result.getStatus());
+      }
 
       processNode(result.getResultTree());
 
       m_generator.close();
       return bytesOut.toString("UTF-8");
+    } catch (IOException e) {
+      //todo: exception handling.  Create ResultStatus 500 and call serializeError
+      throw new RuntimeException("Unable to serialize to json: " + e, e);
+    }
+  }
+
+  @Override
+  public Object serializeError(ResultStatus error) {
+    try {
+      ByteArrayOutputStream bytesOut = init();
+      //m_mapper.writeValue(m_generator, error);
+      m_generator.writeStartObject();
+      m_generator.writeNumberField("status", error.getStatus().getStatus());
+      m_generator.writeStringField("message", error.getMessage());
+      m_generator.writeEndObject();
+      m_generator.close();
+      return bytesOut.toString("UTF-8");
+
     } catch (IOException e) {
       //todo: exception handling
       throw new RuntimeException("Unable to serialize to json: " + e, e);
     }
   }
 
+  private ByteArrayOutputStream init() throws IOException {
+    ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
+    m_generator = createJsonGenerator(bytesOut);
+
+    DefaultPrettyPrinter p = new DefaultPrettyPrinter();
+    p.indentArraysWith(new DefaultPrettyPrinter.Lf2SpacesIndenter());
+    m_generator.setPrettyPrinter(p);
+
+    return bytesOut;
+  }
+
   private void processNode(TreeNode<Resource> node) throws IOException {
     String name = node.getName();
     Resource r = node.getObject();

+ 12 - 4
ambari-server/src/main/java/org/apache/ambari/server/api/services/serializers/ResultSerializer.java

@@ -19,10 +19,9 @@
 package org.apache.ambari.server.api.services.serializers;
 
 
+import org.apache.ambari.server.api.services.ResultStatus;
 import org.apache.ambari.server.api.services.Result;
 
-import javax.ws.rs.core.UriInfo;
-
 /**
  * Format internal result to format expected by client.
  */
@@ -30,9 +29,18 @@ public interface ResultSerializer {
   /**
    * Serialize the given result to a format expected by client.
    *
+   *
    * @param result  internal result
-   * @param uriInfo URL info for request
    * @return the serialized result
    */
-  Object serialize(Result result, UriInfo uriInfo);
+  Object serialize(Result result);
+
+  /**
+   * Serialize an error result to the format expected by the client.
+   *
+   * @param error  the error result
+   *
+   * @return the serialized error result
+   */
+  Object serializeError(ResultStatus error);
 }

+ 28 - 1
ambari-server/src/main/java/org/apache/ambari/server/bootstrap/BSHostStatusCollector.java

@@ -18,7 +18,9 @@
 
 package org.apache.ambari.server.bootstrap;
 
+import java.io.BufferedReader;
 import java.io.File;
+import java.io.FileReader;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
@@ -90,11 +92,36 @@ class BSHostStatusCollector {
         status.setLog("");
       } else {
         String logString = "";
+        BufferedReader reader = null;
         try {
-          logString = FileUtils.readFileToString(log);
+          StringBuilder sb = new StringBuilder();
+          reader = new BufferedReader(new FileReader(log));
+
+          String line = null;
+          while (null != (line = reader.readLine())) {
+            if (line.startsWith("tcgetattr:") || line.startsWith("tput:"))
+              continue;
+
+            if (0 != sb.length() || 0 == line.length())
+              sb.append('\n');
+
+            if (-1 != line.indexOf ("\\n"))
+              sb.append(line.replace("\\n", "\n"));
+            else
+              sb.append(line);
+          }
+          
+          logString = sb.toString();
         } catch (IOException e) {
           LOG.info("Error reading log file " + log);
         }
+        finally {
+          try {
+            reader.close();
+          }
+          catch (Exception e) {
+          }
+        }
         status.setLog(logString);
       }
       hostStatus.add(status);

+ 9 - 1
ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java

@@ -52,7 +52,7 @@ public class Configuration {
   public static final String BOOTSTRAP_SETUP_AGENT_PASSWORD = "bootstrap.setup_agent.password";
   public static final String BOOTSTRAP_MASTER_HOSTNAME = "bootstrap.master_host_name";
   public static final String API_AUTHENTICATE = "api.authenticate";
-
+  public static final String API_USE_SSL = "api.ssl";
   public static final String SRVR_KSTR_DIR_KEY = "security.server.keys_dir";
   public static final String SRVR_CRT_NAME_KEY = "security.server.cert_name";
   public static final String SRVR_KEY_NAME_KEY = "security.server.key_name";
@@ -305,6 +305,14 @@ public class Configuration {
     return ("true".equals(properties.getProperty(API_AUTHENTICATE, "false")));
   }
 
+  /**
+   * Check to see if the API should be authenticated via ssl or not
+   * @return false if not, true if ssl needs to be used.
+   */
+  public boolean getApiSSLAuthentication() {
+    return ("true".equals(properties.getProperty(API_USE_SSL, "false")));
+  }
+
 
   public PersistenceType getPersistenceType() {
     String value = properties.getProperty(PERSISTENCE_IN_MEMORY_KEY, PERSISTENCE_IN_MEMORY_DEFAULT);

+ 3 - 1
ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementController.java

@@ -19,6 +19,8 @@
 package org.apache.ambari.server.controller;
 
 import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.ObjectNotFoundException;
+import org.apache.ambari.server.ParentObjectNotFoundException;
 
 import java.util.Map;
 import java.util.Set;
@@ -47,7 +49,7 @@ public interface AmbariManagementController {
    * @throws AmbariException thrown if the service cannot be created
    */
   public void createServices(Set<ServiceRequest> requests)
-      throws AmbariException;
+      throws AmbariException, ParentObjectNotFoundException;
 
   /**
    * Create the component defined by the attributes in the given request object.

+ 331 - 135
ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java

@@ -19,26 +19,10 @@
 package org.apache.ambari.server.controller;
 
 import java.net.InetAddress;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 import java.util.Map.Entry;
-import java.util.Set;
-import java.util.TreeMap;
-
-import org.apache.ambari.server.AmbariException;
-import org.apache.ambari.server.ClusterNotFoundException;
-import org.apache.ambari.server.HostNotFoundException;
-import org.apache.ambari.server.Role;
-import org.apache.ambari.server.RoleCommand;
-import org.apache.ambari.server.ServiceComponentHostNotFoundException;
-import org.apache.ambari.server.ServiceComponentNotFoundException;
-import org.apache.ambari.server.ServiceNotFoundException;
-import org.apache.ambari.server.StackNotFoundException;
+
+import org.apache.ambari.server.*;
 import org.apache.ambari.server.actionmanager.ActionManager;
 import org.apache.ambari.server.actionmanager.HostRoleCommand;
 import org.apache.ambari.server.actionmanager.RequestStatus;
@@ -258,7 +242,12 @@ public class AmbariManagementControllerImpl implements
         }
       }
 
-      Cluster cluster = clusters.getCluster(request.getClusterName());
+      Cluster cluster;
+      try {
+        cluster = clusters.getCluster(request.getClusterName());
+      } catch (ClusterNotFoundException e) {
+        throw new ParentObjectNotFoundException("Attempted to add a service to a cluster which doesn't exist", e);
+      }
       try {
         Service s = cluster.getService(request.getServiceName());
         if (s != null) {
@@ -298,9 +287,16 @@ public class AmbariManagementControllerImpl implements
         first = false;
         svcNames.append(svcName);
       }
-      throw new IllegalArgumentException("Invalid request"
-          + " contains duplicates within request or already existing services"
-          + ", duplicateServiceNames=" + svcNames.toString());
+      String clusterName = requests.iterator().next().getClusterName();
+      String msg;
+      if (duplicates.size() == 1) {
+        msg = "Attempted to create a service which already exists: "
+            + ", clusterName=" + clusterName  + " serviceName=" + svcNames.toString();
+      } else {
+        msg = "Attempted to create services which already exist: "
+            + ", clusterName=" + clusterName  + " serviceNames=" + svcNames.toString();
+      }
+      throw new DuplicateResourceException(msg);
     }
 
     // now to the real work
@@ -349,7 +345,13 @@ public class AmbariManagementControllerImpl implements
             + " component");
       }
 
-      Cluster cluster = clusters.getCluster(request.getClusterName());
+      Cluster cluster;
+      try {
+        cluster = clusters.getCluster(request.getClusterName());
+      } catch (ClusterNotFoundException e) {
+        throw new ParentObjectNotFoundException(
+            "Attempted to add a component to a cluster which doesn't exist:", e);
+      }
 
       if (request.getServiceName() == null
           || request.getServiceName().isEmpty()) {
@@ -393,8 +395,8 @@ public class AmbariManagementControllerImpl implements
       if (componentNames.get(request.getClusterName())
           .get(request.getServiceName()).contains(request.getComponentName())){
         // throw error later for dup
-        duplicates.add(request.getServiceName()
-            + "-" + request.getComponentName());
+        duplicates.add("[clusterName=" + request.getClusterName() + ", serviceName=" + request.getServiceName() +
+            ", componentName=" + request.getComponentName() + "]");
         continue;
       }
       componentNames.get(request.getClusterName())
@@ -411,13 +413,19 @@ public class AmbariManagementControllerImpl implements
         }
       }
 
-      Service s = cluster.getService(request.getServiceName());
+      Service s;
+      try {
+        s = cluster.getService(request.getServiceName());
+      } catch (ServiceNotFoundException e) {
+        throw new ParentObjectNotFoundException(
+            "Attempted to add a component to a service which doesn't exist:", e);
+      }
       try {
         ServiceComponent sc = s.getServiceComponent(request.getComponentName());
         if (sc != null) {
           // throw error later for dup
-          duplicates.add(request.getServiceName()
-              + "-" + request.getComponentName());
+          duplicates.add("[clusterName=" + request.getClusterName() + ", serviceName=" + request.getServiceName() +
+              ", componentName=" + request.getComponentName() + "]");
           continue;
         }
       } catch (AmbariException e) {
@@ -453,10 +461,13 @@ public class AmbariManagementControllerImpl implements
         first = false;
         names.append(cName);
       }
-      throw new IllegalArgumentException("Invalid request"
-          + " contains duplicates within request or"
-          + " already existing service components"
-          + ", duplicateServiceComponentsNames=" + names.toString());
+      String msg;
+      if (duplicates.size() == 1) {
+        msg = "Attempted to create a component which already exists: ";
+      } else {
+        msg = "Attempted to create components which already exist: ";
+      }
+      throw new DuplicateResourceException(msg + names.toString());
     }
 
 
@@ -529,17 +540,13 @@ public class AmbariManagementControllerImpl implements
         continue;
       }
 
-      if (request.getClusterNames() != null) {
-        for (String clusterName : request.getClusterNames()) {
-          try {
-            clusters.getCluster(clusterName);
-          } catch (ClusterNotFoundException e) {
-            // invalid cluster mapping
-            throw new IllegalArgumentException("Trying to map host"
-                + " to a non-existent cluster"
-                + ", hostname=" + request.getHostname()
-                + ", clusterName=" + clusterName);
-          }
+      if (request.getClusterName() != null) {
+        try {
+          // validate that cluster_name is valid
+          clusters.getCluster(request.getClusterName());
+        } catch (ClusterNotFoundException e) {
+          throw new ParentObjectNotFoundException("Attempted to add a host to a cluster which doesn't exist: "
+              + " clusterName=" + request.getClusterName());
         }
       }
     }
@@ -569,23 +576,19 @@ public class AmbariManagementControllerImpl implements
         first = false;
         names.append(hName);
       }
-      // FIXME throw correct error
-      throw new AmbariException("Some hosts have not been registered with"
-          + " the server"
-          + ", hostnames=" + names.toString());
+
+      throw new IllegalArgumentException("Attempted to add unknown hosts to a cluster.  " +
+          "These hosts have not been registered with the server: " + names.toString());
     }
 
     for (HostRequest request : requests) {
-      Host h = clusters.getHost(request.getHostname());
-      if (request.getClusterNames() != null) {
-        for (String clusterName : request.getClusterNames()) {
-          clusters.mapHostToCluster(request.getHostname(), clusterName);
-        }
+      if (request.getClusterName() != null) {
+        clusters.mapHostToCluster(request.getHostname(), request.getClusterName());
       }
 
       if (request.getHostAttributes() != null) {
-        h = clusters.getHost(request.getHostname());
-        h.setHostAttributes(request.getHostAttributes());
+        clusters.getHost(request.getHostname()).
+            setHostAttributes(request.getHostAttributes());
       }
     }
   }
@@ -615,7 +618,13 @@ public class AmbariManagementControllerImpl implements
             + " when trying to create a hostcomponent");
       }
 
-      Cluster cluster = clusters.getCluster(request.getClusterName());
+      Cluster cluster;
+      try {
+        cluster = clusters.getCluster(request.getClusterName());
+      } catch (ClusterNotFoundException e) {
+        throw new ParentObjectNotFoundException(
+            "Attempted to add a host_component to a cluster which doesn't exist: ", e);
+      }
 
       if (request.getServiceName() == null
           || request.getServiceName().isEmpty()) {
@@ -666,9 +675,8 @@ public class AmbariManagementControllerImpl implements
       if (hostComponentNames.get(request.getClusterName())
           .get(request.getServiceName()).get(request.getComponentName())
           .contains(request.getHostname())) {
-        duplicates.add(request.getServiceName()
-            + "-" + request.getComponentName()
-            + "-" + request.getHostname());
+        duplicates.add("[clusterName=" + request.getClusterName() + ", hostName=" + request.getHostname() +
+            ", componentName=" +request.getComponentName() +']');
         continue;
       }
       hostComponentNames.get(request.getClusterName())
@@ -686,10 +694,24 @@ public class AmbariManagementControllerImpl implements
         }
       }
 
-      Service s = cluster.getService(request.getServiceName());
+      Service s;
+      try {
+        s = cluster.getService(request.getServiceName());
+      } catch (ServiceNotFoundException e) {
+        throw new IllegalArgumentException(
+            "The service[" + request.getServiceName() + "] associated with the component[" +
+            request.getComponentName() + "] doesn't exist for the cluster[" + request.getClusterName() + "]");
+      }
       ServiceComponent sc = s.getServiceComponent(
           request.getComponentName());
-      Host host = clusters.getHost(request.getHostname());
+
+      Host host;
+      try {
+        host = clusters.getHost(request.getHostname());
+      } catch (HostNotFoundException e) {
+        throw new ParentObjectNotFoundException(
+            "Attempted to add a host_component to a host that doesn't exist: ", e);
+      }
       Set<Cluster> mappedClusters =
           clusters.getClustersForHost(request.getHostname());
       boolean validCluster = false;
@@ -713,21 +735,15 @@ public class AmbariManagementControllerImpl implements
         }
       }
       if (!validCluster) {
-        // TODO fix throw correct error
-        throw new AmbariException("Invalid request as host does not belong to"
-            + " given cluster"
-            + ", clusterName=" + request.getClusterName()
-            + ", serviceName=" + request.getServiceName()
-            + ", componentName=" + request.getComponentName()
-            + ", hostname=" + request.getHostname());
+        throw new ParentObjectNotFoundException("Attempted to add a host_component to a host that doesn't exist: " +
+            "clusterName=" + request.getClusterName() + ", hostName=" + request.getHostname());
       }
       try {
         ServiceComponentHost sch = sc.getServiceComponentHost(
             request.getHostname());
         if (sch != null) {
-          duplicates.add(request.getServiceName()
-              + "-" + request.getComponentName()
-              + "-" + request.getHostname());
+          duplicates.add("[clusterName=" + request.getClusterName() + ", hostName=" + request.getHostname() +
+              ", componentName=" +request.getComponentName() +']');
           continue;
         }
       } catch (AmbariException e) {
@@ -751,10 +767,13 @@ public class AmbariManagementControllerImpl implements
         first = false;
         names.append(hName);
       }
-      throw new IllegalArgumentException("Invalid request"
-          + " contains duplicates within request or"
-          + " already existing host components"
-          + ", duplicateServiceComponentHostNames=" + names.toString());
+      String msg;
+      if (duplicates.size() == 1) {
+        msg = "Attempted to create a host_component which already exists: ";
+      } else {
+        msg = "Attempted to create host_component's which already exist: ";
+      }
+      throw new DuplicateResourceException(msg + names.toString());
     }
 
     // now doing actual work
@@ -778,9 +797,7 @@ public class AmbariManagementControllerImpl implements
           && !request.getDesiredState().isEmpty()) {
         State state = State.valueOf(request.getDesiredState());
         sch.setDesiredState(state);
-      } else {
-        sch.setDesiredState(sc.getDesiredState());
-      }
+      } 
 
       sch.setDesiredStackVersion(sc.getDesiredStackVersion());
 
@@ -923,6 +940,7 @@ public class AmbariManagementControllerImpl implements
 
   private synchronized Set<ClusterResponse> getClusters(ClusterRequest request)
       throws AmbariException {
+
     Set<ClusterResponse> response = new HashSet<ClusterResponse>();
 
     if (LOG.isDebugEnabled()) {
@@ -968,7 +986,13 @@ public class AmbariManagementControllerImpl implements
       throw new AmbariException("Invalid arguments, cluster name"
           + " cannot be null");
     }
-    final Cluster cluster = clusters.getCluster(request.getClusterName());
+    String clusterName = request.getClusterName();
+    final Cluster cluster;
+    try {
+      cluster = clusters.getCluster(clusterName);
+    } catch (ObjectNotFoundException e) {
+      throw new ParentObjectNotFoundException("Parent Cluster resource doesn't exist", e);
+    }
 
     Set<ServiceResponse> response = new HashSet<ServiceResponse>();
     if (request.getServiceName() != null) {
@@ -1011,7 +1035,12 @@ public class AmbariManagementControllerImpl implements
           + " should be non-null");
     }
 
-    final Cluster cluster = clusters.getCluster(request.getClusterName());
+    final Cluster cluster;
+    try {
+      cluster = clusters.getCluster(request.getClusterName());
+    } catch (ObjectNotFoundException e) {
+      throw new ParentObjectNotFoundException("Parent Cluster resource doesn't exist", e);
+    }
 
     Set<ServiceComponentResponse> response =
         new HashSet<ServiceComponentResponse>();
@@ -1036,7 +1065,14 @@ public class AmbariManagementControllerImpl implements
         }
         request.setServiceName(serviceName);
       }
-      Service s = cluster.getService(request.getServiceName());
+
+      final Service s;
+      try {
+        s = cluster.getService(request.getServiceName());
+      } catch (ObjectNotFoundException e) {
+        throw new ParentObjectNotFoundException("Parent Service resource doesn't exist", e);
+      }
+
       ServiceComponent sc = s.getServiceComponent(request.getComponentName());
       response.add(sc.convertToResponse());
       return response;
@@ -1078,28 +1114,52 @@ public class AmbariManagementControllerImpl implements
 
   private synchronized Set<HostResponse> getHosts(HostRequest request)
       throws AmbariException {
+
+    //TODO/FIXME host can only belong to a single cluster so get host directly from Cluster
+    //TODO/FIXME what is the requirement for filtering on host attributes?
+
+    List<Host>        hosts;
     Set<HostResponse> response = new HashSet<HostResponse>();
+    Cluster           cluster  = null;
 
-    // FIXME what is the requirement for filtering on host attributes?
-    // FIXME do we need get all hosts in given list of clusters?
+    String clusterName = request.getClusterName();
+    String hostName    = request.getHostname();
 
-    List<Host> hosts = null;
-    if (request.getHostname() != null) {
-      Host h = clusters.getHost(request.getHostname());
-      hosts = new ArrayList<Host>();
-      hosts.add(h);
-    } else {
+    if (clusterName != null) {
+      //validate that cluster exists, throws exception if it doesn't.
+      try {
+        cluster = clusters.getCluster(clusterName);
+      } catch (ObjectNotFoundException e) {
+        throw new ParentObjectNotFoundException("Parent Cluster resource doesn't exist", e);
+      }
+    }
+
+    if (hostName == null) {
       hosts = clusters.getHosts();
+    } else {
+      hosts = new ArrayList<Host>();
+      hosts.add(clusters.getHost(request.getHostname()));
     }
 
     for (Host h : hosts) {
-      HostResponse r = h.convertToResponse();
-      Set<Cluster> cs =
-          clusters.getClustersForHost(h.getHostName());
-      for (Cluster c : cs) {
-        r.getClusterNames().add(c.getClusterName());
+      if (clusterName != null) {
+        if (clusters.getClustersForHost(h.getHostName()).contains(cluster)) {
+          HostResponse r = h.convertToResponse();
+          r.setClusterName(clusterName);
+          response.add(r);
+        } else if (hostName != null) {
+          throw new HostNotFoundException(hostName);
+        }
+      } else {
+        HostResponse r = h.convertToResponse();
+
+        Set<Cluster> clustersForHost = clusters.getClustersForHost(h.getHostName());
+        //todo: host can only belong to a single cluster
+        if (clustersForHost != null && clustersForHost.size() != 0) {
+          r.setClusterName(clustersForHost.iterator().next().getClusterName());
+        }
+        response.add(r);
       }
-      response.add(r);
     }
     return response;
   }
@@ -1108,11 +1168,29 @@ public class AmbariManagementControllerImpl implements
       ServiceComponentHostRequest request) throws AmbariException {
     if (request.getClusterName() == null
         || request.getClusterName().isEmpty()) {
-      throw new AmbariException("Invalid arguments, cluster name should not"
-          + " be null");
+      throw new IllegalArgumentException("Invalid arguments, cluster name should not be null");
+    }
+
+    final Cluster cluster;
+    try {
+      cluster = clusters.getCluster(request.getClusterName());
+    } catch (ClusterNotFoundException e) {
+      throw new ParentObjectNotFoundException("Parent Cluster resource doesn't exist", e);
     }
 
-    final Cluster cluster = clusters.getCluster(request.getClusterName());
+    if (request.getHostname() != null) {
+      try {
+        if (! clusters.getClustersForHost(request.getHostname()).contains(cluster)) {
+          // case where host exists but not associated with given cluster
+          throw new ParentObjectNotFoundException("Parent Host resource doesn't exist",
+              new HostNotFoundException(request.getClusterName(), request.getHostname()));
+        }
+      } catch (HostNotFoundException e) {
+        // creating new HostNotFoundException to add cluster name
+        throw new ParentObjectNotFoundException("Parent Host resource doesn't exist",
+            new HostNotFoundException(request.getClusterName(), request.getHostname()));
+      }
+    }
 
     if (request.getComponentName() != null) {
       if (request.getServiceName() == null
@@ -1124,22 +1202,20 @@ public class AmbariManagementControllerImpl implements
         if (LOG.isDebugEnabled()) {
           LOG.debug("Looking up service name for component"
               + ", componentName=" + request.getComponentName()
-              + ", serviceName=" + serviceName);
+              + ", serviceName=" + serviceName
+              + ", stackInfo=" + stackId.getStackId());
         }
         if (serviceName == null
             || serviceName.isEmpty()) {
-          throw new AmbariException("Could not find service for component"
-              + ", componentName=" + request.getComponentName()
-              + ", clusterName=" + cluster.getClusterName()
-              + ", stackInfo=" + stackId.getStackId());
+          throw new ServiceComponentHostNotFoundException(
+              cluster.getClusterName(), null, request.getComponentName(),request.getHostname());
         }
         request.setServiceName(serviceName);
       }
     }
 
     Set<Service> services = new HashSet<Service>();
-    if (request.getServiceName() != null
-        && !request.getServiceName().isEmpty()) {
+    if (request.getServiceName() != null && !request.getServiceName().isEmpty()) {
       services.add(cluster.getService(request.getServiceName()));
     } else {
       services.addAll(cluster.getServices().values());
@@ -1189,8 +1265,15 @@ public class AmbariManagementControllerImpl implements
             ServiceComponentHostResponse r = sch.convertToResponse();
             response.add(r);
           } catch (ServiceComponentHostNotFoundException e) {
-            // Expected
-            // ignore and continue
+            if (request.getServiceName() != null && request.getComponentName() != null) {
+              throw new ServiceComponentHostNotFoundException(cluster.getClusterName(),
+                  request.getServiceName(), request.getComponentName(),request.getHostname());
+            } else {
+              // ignore this since host_component was not specified
+              // this is an artifact of how we get host_components and can happen
+              // in case where we get all host_components for a host
+            }
+
           }
         } else {
           for (ServiceComponentHost sch :
@@ -1434,6 +1517,7 @@ public class AmbariManagementControllerImpl implements
                 if (oldSchState == State.INIT
                     || oldSchState == State.UNINSTALLED
                     || oldSchState == State.INSTALLED
+                    || oldSchState == State.INSTALLING
                     || oldSchState == State.INSTALL_FAILED) {
                   roleCommand = RoleCommand.INSTALL;
                   event = new ServiceComponentHostInstallEvent(
@@ -1461,14 +1545,18 @@ public class AmbariManagementControllerImpl implements
                 }
                 break;
               case STARTED:
+                StackId stackId = scHost.getDesiredStackVersion();
+                ComponentInfo compInfo = ambariMetaInfo.getComponentCategory(
+                    stackId.getStackName(), stackId.getStackVersion(), scHost.getServiceName(),
+                    scHost.getServiceComponentName());
                 if (oldSchState == State.INSTALLED
-                    || oldSchState == State.START_FAILED) {
+                    || oldSchState == State.START_FAILED || oldSchState == State.STARTING) {
                   roleCommand = RoleCommand.START;
                   event = new ServiceComponentHostStartEvent(
                       scHost.getServiceComponentName(), scHost.getHostName(),
                       nowTimestamp, scHost.getDesiredConfigVersionsRecursive());
                 } else {
-                  throw new AmbariException("Invalid transition for"
+                  String error = "Invalid transition for"
                       + " servicecomponenthost"
                       + ", clusterName=" + cluster.getClusterName()
                       + ", clusterId=" + cluster.getClusterId()
@@ -1476,7 +1564,13 @@ public class AmbariManagementControllerImpl implements
                       + ", componentName=" + scHost.getServiceComponentName()
                       + ", hostname=" + scHost.getHostName()
                       + ", currentState=" + oldSchState
-                      + ", newDesiredState=" + newState);
+                      + ", newDesiredState=" + newState;
+                  if (compInfo.isMaster()) {
+                    throw new AmbariException(error);
+                  } else {
+                    LOG.info("Ignoring: " + error);
+                    continue;
+                  }
                 }
                 break;
               case UNINSTALLED:
@@ -1577,7 +1671,6 @@ public class AmbariManagementControllerImpl implements
             new ServiceComponentHostOpInProgressEvent(null, clientHost,
                 nowTimestamp), cluster.getClusterName(), serviceName);
 
-
         Map<String, Map<String, String>> configurations =
             new TreeMap<String, Map<String, String>>();
         Map<String, Config> allConfigs = cluster.getService(serviceName).getDesiredConfigs();
@@ -1591,6 +1684,10 @@ public class AmbariManagementControllerImpl implements
             smokeTestRole).getExecutionCommand()
             .setConfigurations(configurations);
 
+        // Generate cluster host info
+        stage.getExecutionCommandWrapper(clientHost, smokeTestRole)
+            .getExecutionCommand()
+            .setClusterHostInfo(StageUtils.getClusterHostInfo(cluster));
       }
 
       RoleGraph rg = new RoleGraph(rco);
@@ -1654,6 +1751,7 @@ public class AmbariManagementControllerImpl implements
         if (oldState == State.INIT
             || oldState == State.UNINSTALLED
             || oldState == State.INSTALLED
+            || oldState == State.INSTALLING
             || oldState == State.STARTED
             || oldState == State.START_FAILED
             || oldState == State.INSTALL_FAILED
@@ -1663,6 +1761,7 @@ public class AmbariManagementControllerImpl implements
         break;
       case STARTED:
         if (oldState == State.INSTALLED
+            || oldState == State.STARTING
             || oldState == State.STARTED
             || oldState == State.START_FAILED) {
           return true;
@@ -2296,8 +2395,14 @@ public class AmbariManagementControllerImpl implements
 
       Host h = clusters.getHost(request.getHostname());
 
-      for (String clusterName : request.getClusterNames()) {
-        clusters.mapHostToCluster(request.getHostname(), clusterName);
+      try {
+        //todo: the below method throws an exception when trying to create a duplicate mapping.
+        //todo: this is done to detect duplicates during host create.  Unless it is allowable to
+        //todo: add a host to a cluster by modifying the cluster_name prop, we should not do this mapping here.
+        //todo: Determine if it is allowable to associate a host to a cluster via this mechanism.
+        clusters.mapHostToCluster(request.getHostname(), request.getClusterName());
+      } catch (DuplicateResourceException e) {
+        // do nothing
       }
 
       if (null != request.getHostAttributes())
@@ -2310,8 +2415,10 @@ public class AmbariManagementControllerImpl implements
       if (null != request.getPublicHostName()) {
         h.setPublicHostName(request.getPublicHostName());
       }
-    }
 
+      //todo: if attempt was made to update a property other than those
+      //todo: that are allowed above, should throw exception
+    }
   }
 
   @Override
@@ -2479,8 +2586,8 @@ public class AmbariManagementControllerImpl implements
               + ", newDesiredState=" + newState);
         }
         continue;
-      }
-
+      } 
+      
       if (!isValidStateTransition(oldSchState, newState)) {
         throw new AmbariException("Invalid transition for"
             + " servicecomponenthost"
@@ -2599,14 +2706,12 @@ public class AmbariManagementControllerImpl implements
   @Override
   public RequestStatusResponse deleteServices(Set<ServiceRequest> request)
       throws AmbariException {
-    // TODO Auto-generated method stub
     throw new AmbariException("Delete services not supported");
   }
 
   @Override
   public RequestStatusResponse deleteComponents(
       Set<ServiceComponentRequest> request) throws AmbariException {
-    // TODO Auto-generated method stub
     throw new AmbariException("Delete components not supported");
   }
 
@@ -2619,7 +2724,6 @@ public class AmbariManagementControllerImpl implements
   @Override
   public RequestStatusResponse deleteHostComponents(
       Set<ServiceComponentHostRequest> request) throws AmbariException {
-    // TODO Auto-generated method stub
     throw new AmbariException("Delete host components not supported");
   }
 
@@ -2666,7 +2770,7 @@ public class AmbariManagementControllerImpl implements
 
   public Set<RequestStatusResponse> getRequestsByStatus(RequestsByStatusesRequest request) {
 
-    //TODO implement
+    //TODO implement.  Throw UnsupportedOperationException if it is not supported.
     return Collections.emptySet();
   }
 
@@ -2703,8 +2807,17 @@ public class AmbariManagementControllerImpl implements
         response.add(getRequestStatusResponse(requestId.longValue()));
       }
     } else {
-      response.add(getRequestStatusResponse(
-          request.getRequestId().longValue()));
+      RequestStatusResponse requestStatusResponse = getRequestStatusResponse(
+          request.getRequestId().longValue());
+
+      //todo: correlate request with cluster
+      if (requestStatusResponse.getTasks().size() == 0) {
+        //todo: should be thrown lower in stack but we only want to throw if id was specified
+        //todo: and we currently iterate over all id's and invoke for each if id is not specified
+        throw new ObjectNotFoundException("Request resource doesn't exist.");
+      } else {
+        response.add(requestStatusResponse);
+      }
     }
     return response;
   }
@@ -2733,11 +2846,18 @@ public class AmbariManagementControllerImpl implements
   }
 
   @Override
-  public Set<ClusterResponse> getClusters(Set<ClusterRequest> requests)
-      throws AmbariException {
+  public Set<ClusterResponse> getClusters(Set<ClusterRequest> requests) throws AmbariException {
     Set<ClusterResponse> response = new HashSet<ClusterResponse>();
     for (ClusterRequest request : requests) {
-      response.addAll(getClusters(request));
+      try {
+        response.addAll(getClusters(request));
+      } catch (ClusterNotFoundException e) {
+        if (requests.size() == 1) {
+          // only throw exception if 1 request.
+          // there will be > 1 request in case of OR predicate
+          throw e;
+        }
+      }
     }
     return response;
   }
@@ -2747,7 +2867,15 @@ public class AmbariManagementControllerImpl implements
       throws AmbariException {
     Set<ServiceResponse> response = new HashSet<ServiceResponse>();
     for (ServiceRequest request : requests) {
-      response.addAll(getServices(request));
+      try {
+        response.addAll(getServices(request));
+      } catch (ServiceNotFoundException e) {
+        if (requests.size() == 1) {
+          // only throw exception if 1 request.
+          // there will be > 1 request in case of OR predicate
+          throw e;
+        }
+      }
     }
     return response;
   }
@@ -2758,7 +2886,15 @@ public class AmbariManagementControllerImpl implements
     Set<ServiceComponentResponse> response =
         new HashSet<ServiceComponentResponse>();
     for (ServiceComponentRequest request : requests) {
-      response.addAll(getComponents(request));
+      try {
+        response.addAll(getComponents(request));
+      } catch (ServiceComponentNotFoundException e) {
+        if (requests.size() == 1) {
+          // only throw exception if 1 request.
+          // there will be > 1 request in case of OR predicate
+          throw e;
+        }
+      }
     }
     return response;
   }
@@ -2768,7 +2904,15 @@ public class AmbariManagementControllerImpl implements
       throws AmbariException {
     Set<HostResponse> response = new HashSet<HostResponse>();
     for (HostRequest request : requests) {
-      response.addAll(getHosts(request));
+      try {
+        response.addAll(getHosts(request));
+      } catch (HostNotFoundException e) {
+        if (requests.size() == 1) {
+          // only throw exception if 1 request.
+          // there will be > 1 request in case of OR predicate
+          throw e;
+        }
+      }
     }
     return response;
   }
@@ -2779,7 +2923,48 @@ public class AmbariManagementControllerImpl implements
     Set<ServiceComponentHostResponse> response =
         new HashSet<ServiceComponentHostResponse>();
     for (ServiceComponentHostRequest request : requests) {
-      response.addAll(getHostComponents(request));
+      try {
+        response.addAll(getHostComponents(request));
+      } catch (ServiceComponentHostNotFoundException e) {
+        if (requests.size() == 1) {
+          // only throw exception if 1 request.
+          // there will be > 1 request in case of OR predicate
+          throw e;
+        }
+      } catch (ServiceNotFoundException e) {
+        if (requests.size() == 1) {
+          // only throw exception if 1 request.
+          // there will be > 1 request in case of OR predicate
+          // In 'OR' case, a host_component may be included in predicate
+          // that has no corresponding service
+          throw e;
+        }
+      } catch (ServiceComponentNotFoundException e) {
+        if (requests.size() == 1) {
+          // only throw exception if 1 request.
+          // there will be > 1 request in case of OR predicate
+          // In 'OR' case, a host_component may be included in predicate
+          // that has no corresponding component
+          throw e;
+        }
+      } catch (ParentObjectNotFoundException e) {
+        // If there is only one request, always throw exception.
+        // There will be > 1 request in case of OR predicate.
+
+        // For HostNotFoundException, only throw exception if host_name is
+        // provided in URL.  If host_name is part of query, don't throw exception.
+        boolean throwException = true;
+        if (requests.size() > 1 && HostNotFoundException.class.isInstance(e.getCause())) {
+          for (ServiceComponentHostRequest r : requests) {
+            if (r.getHostname() == null) {
+              // host_name provided in query since all requests don't have host_name set
+              throwException = false;
+              break;
+            }
+          }
+        }
+        if (throwException) throw e;
+      }
     }
     return response;
   }
@@ -2818,12 +3003,17 @@ public class AmbariManagementControllerImpl implements
 
         User u = users.getAnyUser(r.getUsername());
         if (null == u) {
-          throw new AmbariException("Cannot find user '"
-              + r.getUsername() + "'");
+          if (requests.size() == 1) {
+            // only throw exceptin if there is a single request
+            // if there are multiple requests, this indicates an OR predicate
+            throw new ObjectNotFoundException("Cannot find user '"
+                + r.getUsername() + "'");
+          }
+        } else {
+          UserResponse resp = new UserResponse(u.getUserName(), u.isLdapUser());
+          resp.setRoles(new HashSet<String>(u.getRoles()));
+          responses.add(resp);
         }
-        UserResponse resp = new UserResponse(u.getUserName(), u.isLdapUser());
-        resp.setRoles(new HashSet<String>(u.getRoles()));
-        responses.add(resp);
       }
     }
 
@@ -2933,7 +3123,6 @@ public class AmbariManagementControllerImpl implements
 
     stage.getExecutionCommandWrapper(hostName, actionRequest.getActionName()).getExecutionCommand()
         .setRoleParams(actionRequest.getParameters());
-    
 
     Map<String, Map<String, String>> configurations = new TreeMap<String, Map<String, String>>();
     Map<String, Config> allConfigs = clusters.getCluster(clusterName)
@@ -2947,6 +3136,13 @@ public class AmbariManagementControllerImpl implements
     stage.getExecutionCommandWrapper(hostName,
         actionRequest.getActionName()).getExecutionCommand()
         .setConfigurations(configurations); 
+    
+    // Generate cluster host info
+    stage
+        .getExecutionCommandWrapper(hostName, actionRequest.getActionName())
+        .getExecutionCommand()
+        .setClusterHostInfo(
+            StageUtils.getClusterHostInfo(clusters.getCluster(clusterName)));
   }
 
   private void addDecommissionDatanodeAction(

+ 70 - 52
ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java

@@ -1,20 +1,20 @@
 /**
-* Licensed to the Apache Software Foundation (ASF) under one
-* or more contributor license agreements.  See the NOTICE file
-* distributed with this work for additional information
-* regarding copyright ownership.  The ASF licenses this file
-* to you under the Apache License, Version 2.0 (the
-* "License"); you may not use this file except in compliance
-* with the License.  You may obtain a copy of the License at
-*
-*     http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
+ * 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 org.apache.ambari.server.controller;
 
@@ -71,10 +71,11 @@ import com.sun.jersey.spi.container.servlet.ServletContainer;
 @Singleton
 public class AmbariServer {
   private static Logger LOG = LoggerFactory.getLogger(AmbariServer.class);
-  public static final int AGENT_ONE_WAY_AUTH = 4080;
-  public static final int AGENT_TWO_WAY_AUTH = 8443;
+  public static final int AGENT_ONE_WAY_AUTH = 8440;
+  public static final int AGENT_TWO_WAY_AUTH = 8441;
+  public static final int CLIENT_SSL_API_PORT = 8443;
   public static final int CLIENT_API_PORT = 8080;
- 
+
   private Server server = null;
   private Server serverForAgent = null;
 
@@ -132,8 +133,8 @@ public class AmbariServer {
       String[] contextLocations = {SPRING_CONTEXT_LOCATION};
       ClassPathXmlApplicationContext springAppContext = new
           ClassPathXmlApplicationContext(contextLocations, parentSpringAppContext);
-       //setting ambari web context
- 
+      //setting ambari web context
+
       ServletContextHandler root = new ServletContextHandler(server, CONTEXT_PATH, 
           ServletContextHandler.NO_SECURITY | ServletContextHandler.SECURITY |
           ServletContextHandler.SECURITY | ServletContextHandler.SESSIONS);
@@ -143,7 +144,7 @@ public class AmbariServer {
       springWebAppContext.setParent(springAppContext);
       /* Configure web app context */
       root.setResourceBase(configs.getWebAppDir());
-      
+
       root.getServletContext().setAttribute(
           WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,
           springWebAppContext);
@@ -167,11 +168,11 @@ public class AmbariServer {
       if (configs.getApiAuthentication()) {
         root.addFilter(new FilterHolder(springSecurityFilter), "/api/*", 1);
       }
-      
-      
+
+
       //Secured connector for 2-way auth
       SslSelectChannelConnector sslConnectorTwoWay = new  
-            SslSelectChannelConnector();
+          SslSelectChannelConnector();
       sslConnectorTwoWay.setPort(AGENT_TWO_WAY_AUTH);
 
       Map<String, String> configsMap = configs.getConfigsMap();
@@ -186,7 +187,7 @@ public class AmbariServer {
       sslConnectorTwoWay.setKeystoreType("PKCS12");
       sslConnectorTwoWay.setTruststoreType("PKCS12");
       sslConnectorTwoWay.setNeedClientAuth(true);
-      
+
       //Secured connector for 1-way auth
       //SslSelectChannelConnector sslConnectorOneWay = new SslSelectChannelConnector();
       SslContextFactory contextFactory = new SslContextFactory(true);
@@ -197,42 +198,42 @@ public class AmbariServer {
       // sslConnectorOneWay.setTruststore(keystore);
       contextFactory.setKeyStorePassword(srvrCrtPass);
       // sslConnectorOneWay.setPassword(srvrCrtPass);
-      
+
       contextFactory.setKeyManagerPassword(srvrCrtPass);
 
       // sslConnectorOneWay.setKeyPassword(srvrCrtPass);
-      
+
       contextFactory.setTrustStorePassword(srvrCrtPass);
       //sslConnectorOneWay.setTrustPassword(srvrCrtPass);
-      
+
       contextFactory.setKeyStoreType("PKCS12");
       //sslConnectorOneWay.setKeystoreType("PKCS12");
       contextFactory.setTrustStoreType("PKCS12");
-     
+
       //sslConnectorOneWay.setTruststoreType("PKCS12");
       contextFactory.setNeedClientAuth(false);
       // sslConnectorOneWay.setWantClientAuth(false);
       // sslConnectorOneWay.setNeedClientAuth(false);
       SslSelectChannelConnector sslConnectorOneWay = new SslSelectChannelConnector(contextFactory);
       sslConnectorOneWay.setPort(AGENT_ONE_WAY_AUTH);
-      
+
       serverForAgent.setConnectors(new Connector[]{ sslConnectorOneWay, sslConnectorTwoWay});
-      
+
       ServletHolder sh = new ServletHolder(ServletContainer.class);
       sh.setInitParameter("com.sun.jersey.config.property.resourceConfigClass",
-              "com.sun.jersey.api.core.PackagesResourceConfig");
+          "com.sun.jersey.api.core.PackagesResourceConfig");
       sh.setInitParameter("com.sun.jersey.config.property.packages",
-              "org.apache.ambari.server.api.rest;" +
+          "org.apache.ambari.server.api.rest;" +
               "org.apache.ambari.server.api.services;" +
-              "org.apache.ambari.eventdb.webservice");
+          "org.apache.ambari.eventdb.webservice");
       root.addServlet(sh, "/api/v1/*");
       sh.setInitOrder(2);
-      
+
       ServletHolder agent = new ServletHolder(ServletContainer.class);
       agent.setInitParameter("com.sun.jersey.config.property.resourceConfigClass",
-              "com.sun.jersey.api.core.PackagesResourceConfig");
+          "com.sun.jersey.api.core.PackagesResourceConfig");
       agent.setInitParameter("com.sun.jersey.config.property.packages",
-              "org.apache.ambari.server.agent.rest");
+          "org.apache.ambari.server.agent.rest");
       agent.setInitParameter("com.sun.jersey.api.json.POJOMappingFeature",
           "true");
       agentroot.addServlet(agent, "/agent/v1/*");
@@ -240,29 +241,46 @@ public class AmbariServer {
 
       ServletHolder cert = new ServletHolder(ServletContainer.class);
       cert.setInitParameter("com.sun.jersey.config.property.resourceConfigClass",
-              "com.sun.jersey.api.core.PackagesResourceConfig");
+          "com.sun.jersey.api.core.PackagesResourceConfig");
       cert.setInitParameter("com.sun.jersey.config.property.packages",
-              "org.apache.ambari.server.security.unsecured.rest");
+          "org.apache.ambari.server.security.unsecured.rest");
       agentroot.addServlet(cert, "/*");
       cert.setInitOrder(4);
 
       ServletHolder resources = new ServletHolder(ServletContainer.class);
       resources.setInitParameter("com.sun.jersey.config.property.resourceConfigClass",
-              "com.sun.jersey.api.core.PackagesResourceConfig");
+          "com.sun.jersey.api.core.PackagesResourceConfig");
       resources.setInitParameter("com.sun.jersey.config.property.packages",
-        "org.apache.ambari.server.resources.api.rest");
+          "org.apache.ambari.server.resources.api.rest");
       root.addServlet(resources, "/resources/*");
       resources.setInitOrder(6);
-      
+
       //Set jetty thread pool
       serverForAgent.setThreadPool(new QueuedThreadPool(25));
       server.setThreadPool(new QueuedThreadPool(25));
-      
+
       /* Configure the API server to use the NIO connectors */
-      SelectChannelConnector apiConnector = new SelectChannelConnector();
-      apiConnector.setPort(CLIENT_API_PORT);
+      SelectChannelConnector apiConnector;
+
+      if (configs.getApiSSLAuthentication()) {
+        SslSelectChannelConnector sapiConnector = new SslSelectChannelConnector();
+        sapiConnector.setPort(CLIENT_SSL_API_PORT);
+        sapiConnector.setKeystore(keystore);
+        sapiConnector.setTruststore(keystore);
+        sapiConnector.setPassword(srvrCrtPass);
+        sapiConnector.setKeyPassword(srvrCrtPass);
+        sapiConnector.setTrustPassword(srvrCrtPass);
+        sapiConnector.setKeystoreType("PKCS12");
+        sapiConnector.setTruststoreType("PKCS12");
+        apiConnector = sapiConnector;
+      } 
+      else  {
+        apiConnector = new SelectChannelConnector();
+        apiConnector.setPort(CLIENT_API_PORT);
+      }
+
       server.addConnector(apiConnector);
-      
+
       server.setStopAtShutdown(true);
       serverForAgent.setStopAtShutdown(true);
       springAppContext.start();
@@ -305,16 +323,16 @@ public class AmbariServer {
       manager.start();
       LOG.info("********* Started ActionManager **********");
 
-//TODO: Remove this code when APIs are ready for testing.
-//      RequestInjectorForTest testInjector = new RequestInjectorForTest(controller, clusters);
-//      Thread testInjectorThread = new Thread(testInjector);
-//      testInjectorThread.start();
+      //TODO: Remove this code when APIs are ready for testing.
+      //      RequestInjectorForTest testInjector = new RequestInjectorForTest(controller, clusters);
+      //      Thread testInjectorThread = new Thread(testInjector);
+      //      testInjectorThread.start();
 
       server.join();
       LOG.info("Joined the Server");
     } catch(BindException bindException) {
       LOG.error("Could not bind to server port - instance may already be running. " +
-        "Terminating this instance.", bindException);
+          "Terminating this instance.", bindException);
       throw bindException;
     }
   }

+ 11 - 21
ambari-server/src/main/java/org/apache/ambari/server/controller/HostRequest.java

@@ -26,13 +26,13 @@ public class HostRequest {
 
   private String hostname;
   private String publicHostname;
-  private List<String> clusterNames; // CREATE/UPDATE
+  private String clusterName; // CREATE/UPDATE
   private Map<String, String> hostAttributes; // CREATE/UPDATE
   private String rackInfo;
 
-  public HostRequest(String hostname, List<String> clusterNames, Map<String, String> hostAttributes) {
+  public HostRequest(String hostname, String clusterName, Map<String, String> hostAttributes) {
     this.hostname = hostname;
-    this.clusterNames = clusterNames;
+    this.clusterName = clusterName;
     this.hostAttributes = hostAttributes;
   }
 
@@ -44,12 +44,12 @@ public class HostRequest {
     this.hostname = hostname;
   }
 
-  public List<String> getClusterNames() {
-    return clusterNames;
+  public String getClusterName() {
+    return clusterName;
   }
 
-  public void setClusterNames(List<String> clusterNames) {
-    this.clusterNames = clusterNames;
+  public void setClusterName(String clusterName) {
+    this.clusterName = clusterName;
   }
 
   public Map<String, String> getHostAttributes() {
@@ -78,19 +78,9 @@ public class HostRequest {
 
   public String toString() {
     StringBuilder sb = new StringBuilder();
-    sb.append("{"
-        + ", hostname=" + hostname
-        + ", clusterNames=[");
-    if (clusterNames != null) {
-      for (int i = 0; i < clusterNames.size(); ++i) {
-        if (i != 0) {
-          sb.append(",");
-        }
-        sb.append(clusterNames.get(i));
-      }
-    }
+    sb.append("{ hostname=").append(hostname).append(", clusterName=").append(clusterName);
     if (hostAttributes != null) {
-      sb.append("], hostAttributes=[");
+      sb.append(", hostAttributes=[");
       int i = 0;
       for (Entry<String, String> attr : hostAttributes.entrySet()) {
         if (i != 0) {
@@ -99,9 +89,9 @@ public class HostRequest {
         ++i;
         sb.append(attr.getKey() + "=" + attr.getValue());
       }
+      sb.append(']');
     }
-    sb.append("] }");
+    sb.append(" }");
     return sb.toString();
   }
-
 }

+ 10 - 9
ambari-server/src/main/java/org/apache/ambari/server/controller/HostResponse.java

@@ -33,7 +33,7 @@ public class HostResponse {
 
   private String hostname;
 
-  private Set<String> clusterNames;
+  private String clusterName;
 
   /**
    * Host IP if ipv4 interface available
@@ -120,7 +120,7 @@ public class HostResponse {
    */
   private String hostState;
 
-  public HostResponse(String hostname, Set<String> clusterNames,
+  public HostResponse(String hostname, String clusterName,
                       String ipv4, String ipv6, int cpuCount, String osArch, String osType,
                       String osInfo, long availableMemBytes, long totalMemBytes,
                       List<DiskInfo> disksInfo, long lastHeartbeatTime,
@@ -129,7 +129,7 @@ public class HostResponse {
                       HostHealthStatus healthStatus, String hostState) {
     super();
     this.hostname = hostname;
-    this.clusterNames = clusterNames;
+    this.clusterName = clusterName;
     this.ipv4 = ipv4;
     this.ipv6 = ipv6;
     this.cpuCount = cpuCount;
@@ -148,8 +148,9 @@ public class HostResponse {
     this.setHostState(hostState);
   }
 
+  //todo: why are we passing in empty strings for host/cluster name instead of null?
   public HostResponse(String hostname) {
-    this(hostname, new HashSet<String>(), "", "",
+    this(hostname, "", "", "",
         0, "", "",
         "", 0, 0, new ArrayList<DiskInfo>(),
         0, 0, "",
@@ -174,15 +175,15 @@ public class HostResponse {
   /**
    * @return the clusterNames
    */
-  public Set<String> getClusterNames() {
-    return clusterNames;
+  public String getClusterName() {
+    return clusterName;
   }
 
   /**
-   * @param clusterNames the clusterNames to set
+   * @param clusterName the name of the associated cluster
    */
-  public void setClusterNames(Set<String> clusterNames) {
-    this.clusterNames = clusterNames;
+  public void setClusterName(String clusterName) {
+    this.clusterName = clusterName;
   }
 
   /**

+ 5 - 1
ambari-server/src/main/java/org/apache/ambari/server/controller/ganglia/GangliaHostProvider.java

@@ -17,6 +17,8 @@
  */
 package org.apache.ambari.server.controller.ganglia;
 
+import org.apache.ambari.server.controller.spi.SystemException;
+
 /**
  *  Provider of Ganglia host information.
  */
@@ -28,6 +30,8 @@ public interface GangliaHostProvider {
    * @param clusterName  the cluster name
    *
    * @return the Ganglia server
+   *
+   * @throws SystemException if unable to get the Ganglia server host name
    */
-  public String getGangliaCollectorHostName(String clusterName);
+  public String getGangliaCollectorHostName(String clusterName) throws SystemException;
 }

+ 20 - 7
ambari-server/src/main/java/org/apache/ambari/server/controller/ganglia/GangliaPropertyProvider.java

@@ -18,7 +18,6 @@
 
 package org.apache.ambari.server.controller.ganglia;
 
-import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.controller.internal.PropertyInfo;
 import org.apache.ambari.server.controller.spi.*;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
@@ -30,6 +29,7 @@ import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -102,11 +102,10 @@ public abstract class GangliaPropertyProvider implements PropertyProvider {
   // ----- PropertyProvider --------------------------------------------------
 
   @Override
-  public Set<Resource> populateResources(Set<Resource> resources,
-                                         Request request,
-                                         Predicate predicate) throws AmbariException{
+  public Set<Resource> populateResources(Set<Resource> resources, Request request, Predicate predicate)
+      throws SystemException {
 
-    Set<String> ids = PropertyHelper.getRequestPropertyIds(getPropertyIds(), request, predicate);
+    Set<String> ids = PropertyHelper.getRequestPropertyIds(propertyIds, request, predicate);
     if (ids.isEmpty()) {
       return resources;
     }
@@ -130,6 +129,16 @@ public abstract class GangliaPropertyProvider implements PropertyProvider {
     return propertyIds;
   }
 
+  @Override
+  public Set<String> checkPropertyIds(Set<String> propertyIds) {
+    if (!this.propertyIds.containsAll(propertyIds)) {
+      Set<String> unsupportedPropertyIds = new HashSet<String>(propertyIds);
+      unsupportedPropertyIds.removeAll(this.propertyIds);
+      return unsupportedPropertyIds;
+    }
+    return Collections.emptySet();
+  }
+
 
   // ----- GangliaPropertyProvider -------------------------------------------
 
@@ -256,12 +265,14 @@ public abstract class GangliaPropertyProvider implements PropertyProvider {
    * @param temporalInfo  the temporal information
    *
    * @return the spec
+   *
+   * @throws SystemException if unable to get the Ganglia Collector host name
    */
   private String getSpec(String clusterName,
                          Set<String> clusterSet,
                          Set<String> hostSet,
                          Set<String> metricSet,
-                         TemporalInfo temporalInfo) {
+                         TemporalInfo temporalInfo) throws SystemException {
 
     String clusters = getSetString(clusterSet, -1);
     String hosts    = getSetString(hostSet, -1);
@@ -397,8 +408,10 @@ public abstract class GangliaPropertyProvider implements PropertyProvider {
      * Populate the associated resources by making the rrd request.
      *
      * @return a collection of populated resources
+     *
+     * @throws SystemException if unable to populate the resources
      */
-    public Collection<Resource> populateResources() {
+    public Collection<Resource> populateResources() throws SystemException {
 
       String spec = getSpec(clusterName, clusterSet, hostSet, metrics.keySet(), temporalInfo);
       Collection<Resource> populatedResources = new HashSet<Resource>();

+ 24 - 12
ambari-server/src/main/java/org/apache/ambari/server/controller/ganglia/GangliaReportPropertyProvider.java

@@ -18,7 +18,6 @@
 
 package org.apache.ambari.server.controller.ganglia;
 
-import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.controller.internal.PropertyInfo;
 import org.apache.ambari.server.controller.spi.*;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
@@ -29,6 +28,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -82,7 +82,9 @@ public class GangliaReportPropertyProvider implements PropertyProvider {
   // ----- PropertyProvider --------------------------------------------------
 
   @Override
-  public Set<Resource> populateResources(Set<Resource> resources, Request request, Predicate predicate) throws AmbariException{
+  public Set<Resource> populateResources(Set<Resource> resources, Request request, Predicate predicate)
+      throws SystemException {
+
     Set<Resource> keepers = new HashSet<Resource>();
     for (Resource resource : resources) {
       if (populateResource(resource, request, predicate)) {
@@ -97,6 +99,16 @@ public class GangliaReportPropertyProvider implements PropertyProvider {
     return propertyIds;
   }
 
+  @Override
+  public Set<String> checkPropertyIds(Set<String> propertyIds) {
+    if (!this.propertyIds.containsAll(propertyIds)) {
+      Set<String> unsupportedPropertyIds = new HashSet<String>(propertyIds);
+      unsupportedPropertyIds.removeAll(this.propertyIds);
+      return unsupportedPropertyIds;
+    }
+    return Collections.emptySet();
+  }
+
 
   // ----- helper methods ----------------------------------------------------
 
@@ -109,11 +121,12 @@ public class GangliaReportPropertyProvider implements PropertyProvider {
    *
    * @return true if the resource was successfully populated with the requested properties
    *
-   * @throws AmbariException thrown if the resource cannot be populated
+   * @throws SystemException if unable to populate the resource
    */
-  private boolean populateResource(Resource resource, Request request, Predicate predicate) throws AmbariException{
+  private boolean populateResource(Resource resource, Request request, Predicate predicate)
+      throws SystemException {
 
-    if (getPropertyIds().isEmpty()) {
+    if (propertyIds.isEmpty()) {
       return true;
     }
     String clusterName = (String) resource.getPropertyValue(clusterNamePropertyId);
@@ -127,16 +140,13 @@ public class GangliaReportPropertyProvider implements PropertyProvider {
     }
 
     setProperties(resource, clusterName, request,
-        PropertyHelper.getRequestPropertyIds(getPropertyIds(), request, predicate));
+        PropertyHelper.getRequestPropertyIds(propertyIds, request, predicate));
 
     return true;
   }
 
-  private boolean setProperties(Resource resource,
-                                String clusterName,
-                                Request request,
-                                Set<String> ids) {
-
+  private boolean setProperties(Resource resource, String clusterName, Request request, Set<String> ids)
+      throws SystemException {
 
     Map<String, Map<String, String>> propertyIdMaps = getPropertyIdMaps(request, ids);
 
@@ -222,8 +232,10 @@ public class GangliaReportPropertyProvider implements PropertyProvider {
    * @param report          the report
    *
    * @return the spec
+   *
+   * @throws SystemException if unable to ge the Ganglia Collector host name
    */
-  protected String getSpec(String clusterName, String report) {
+  protected String getSpec(String clusterName, String report) throws SystemException {
 
     StringBuilder sb = new StringBuilder();
 

+ 18 - 0
ambari-server/src/main/java/org/apache/ambari/server/controller/ganglia/MetricsMapping.java

@@ -1,5 +1,23 @@
 package org.apache.ambari.server.controller.ganglia;
 
+/**
+ * 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.
+ */
+
 /**
  *
  */

+ 38 - 16
ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ActionResourceProvider.java

@@ -20,17 +20,13 @@ package org.apache.ambari.server.controller.internal;
 import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.controller.ActionRequest;
 import org.apache.ambari.server.controller.AmbariManagementController;
-import org.apache.ambari.server.controller.spi.Predicate;
-import org.apache.ambari.server.controller.spi.Request;
-import org.apache.ambari.server.controller.spi.RequestStatus;
-import org.apache.ambari.server.controller.spi.Resource;
-import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
+import org.apache.ambari.server.controller.spi.*;
+import org.apache.ambari.server.controller.RequestStatusResponse;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
 
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
@@ -61,32 +57,60 @@ class ActionResourceProvider extends ResourceProviderImpl {
   }
 
   @Override
-  public RequestStatus createResources(Request request) throws AmbariException, UnsupportedPropertyException {
-    checkRequestProperties(Resource.Type.Action, request);
-    Set<ActionRequest> requests = new HashSet<ActionRequest>();
+  public RequestStatus createResources(Request request)
+      throws SystemException,
+             UnsupportedPropertyException,
+             ResourceAlreadyExistsException,
+             NoSuchParentResourceException {
+
+    final Set<ActionRequest> requests = new HashSet<ActionRequest>();
     for (Map<String, Object> propertyMap : request.getProperties()) {
       requests.add(getRequest(propertyMap));
     }
-    return getRequestStatus(getManagementController().createActions(requests));
+    return getRequestStatus(createResources(new Command<RequestStatusResponse>() {
+      @Override
+      public RequestStatusResponse invoke() throws AmbariException {
+        return getManagementController().createActions(requests);
+      }
+    }));
   }
 
   @Override
   public Set<Resource> getResources(Request request, Predicate predicate)
-      throws AmbariException, UnsupportedPropertyException {
+      throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
     throw new UnsupportedOperationException("Not currently supported.");
   }
 
   @Override
   public RequestStatus updateResources(Request request, Predicate predicate)
-      throws AmbariException, UnsupportedPropertyException {
+      throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
     throw new UnsupportedOperationException("Not currently supported.");
   }
 
   @Override
-  public RequestStatus deleteResources(Predicate predicate) throws AmbariException, UnsupportedPropertyException {
+  public RequestStatus deleteResources(Predicate predicate)
+      throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
     throw new UnsupportedOperationException("Not currently supported.");
   }
 
+  @Override
+  public Set<String> checkPropertyIds(Set<String> propertyIds) {
+    propertyIds = super.checkPropertyIds(propertyIds);
+
+    if (propertyIds.isEmpty()) {
+      return propertyIds;
+    }
+    Set<String> unsupportedProperties = new HashSet<String>();
+
+    for (String propertyId : propertyIds) {
+      String propertyCategory = PropertyHelper.getPropertyCategory(propertyId);
+      if (propertyCategory == null || !propertyCategory.equals("parameters")) {
+        unsupportedProperties.add(propertyId);
+      }
+    }
+    return unsupportedProperties;
+  }
+
   @Override
   protected Set<String> getPKPropertyIds() {
     return pkPropertyIds;
@@ -94,9 +118,7 @@ class ActionResourceProvider extends ResourceProviderImpl {
 
   private ActionRequest getRequest(Map<String, Object> properties) {
     Map<String, String> params = new HashMap<String, String>();
-    Iterator<Entry<String, Object>> it1 = properties.entrySet().iterator();
-    while (it1.hasNext()) {
-      Entry<String, Object> entry = it1.next();
+    for (Entry<String, Object> entry : properties.entrySet()) {
       String propertyid = entry.getKey();
       if (PropertyHelper.getPropertyCategory(propertyid).equals("parameters")
           && null != entry.getValue()) {

+ 126 - 83
ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterControllerImpl.java

@@ -19,16 +19,7 @@
 package org.apache.ambari.server.controller.internal;
 
 import org.apache.ambari.server.controller.spi.ProviderModule;
-import org.apache.ambari.server.AmbariException;
-import org.apache.ambari.server.controller.spi.ClusterController;
-import org.apache.ambari.server.controller.spi.Predicate;
-import org.apache.ambari.server.controller.spi.PropertyProvider;
-import org.apache.ambari.server.controller.spi.Request;
-import org.apache.ambari.server.controller.spi.RequestStatus;
-import org.apache.ambari.server.controller.spi.Resource;
-import org.apache.ambari.server.controller.spi.ResourceProvider;
-import org.apache.ambari.server.controller.spi.Schema;
-import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
+import org.apache.ambari.server.controller.spi.*;
 import org.apache.ambari.server.controller.utilities.PredicateBuilder;
 import org.apache.ambari.server.controller.utilities.PredicateHelper;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
@@ -85,9 +76,12 @@ public class ClusterControllerImpl implements ClusterController {
   // ----- ClusterController -------------------------------------------------
 
   @Override
-  public Iterable<Resource> getResources(Resource.Type type,
-                                         Request request, Predicate predicate)
-      throws AmbariException, UnsupportedPropertyException{
+  public Iterable<Resource> getResources(Resource.Type type, Request request, Predicate predicate)
+      throws UnsupportedPropertyException,
+             SystemException,
+             NoSuchParentResourceException,
+             NoSuchResourceException {
+
     ResourceProvider provider = ensureResourceProvider(type);
     ensurePropertyProviders(type);
     Set<Resource> resources;
@@ -99,6 +93,8 @@ public class ClusterControllerImpl implements ClusterController {
           + provider.getClass().getName()
           + " for request type " + type.toString());
 
+      checkProperties(type, request, predicate);
+
       resources = provider.getResources(request, predicate);
       resources = populateResources(type, resources, request, predicate);
     }
@@ -121,44 +117,59 @@ public class ClusterControllerImpl implements ClusterController {
   }
 
   @Override
-  public RequestStatus createResources(Resource.Type type,
-                                       Request request)
-      throws AmbariException, UnsupportedPropertyException {
+  public RequestStatus createResources(Resource.Type type, Request request)
+      throws UnsupportedPropertyException,
+             SystemException,
+             ResourceAlreadyExistsException,
+             NoSuchParentResourceException {
+
     ResourceProvider provider = ensureResourceProvider(type);
     if (provider != null) {
+
+      checkProperties(type, request, null);
+
       return provider.createResources(request);
     }
     return null;
   }
 
   @Override
-  public RequestStatus updateResources(Resource.Type type,
-                                       Request request,
-                                       Predicate predicate)
-      throws AmbariException, UnsupportedPropertyException {
+  public RequestStatus updateResources(Resource.Type type, Request request, Predicate predicate)
+      throws UnsupportedPropertyException,
+             SystemException,
+             NoSuchResourceException,
+             NoSuchParentResourceException {
+
     ResourceProvider provider = ensureResourceProvider(type);
     if (provider != null) {
-      predicate = checkPredicate(type, request, predicate);
-      if (predicate == null) {
-        return null;
+
+      if (!checkProperties(type, request, predicate)) {
+        predicate = resolvePredicate(type, predicate);
+        if (predicate == null) {
+          return null;
+        }
       }
-      return provider.updateResources(request, predicate);
+        return provider.updateResources(request, predicate);
     }
     return null;
   }
 
   @Override
-  public RequestStatus deleteResources(Resource.Type type,
-                                       Predicate predicate)
-      throws AmbariException, UnsupportedPropertyException {
+  public RequestStatus deleteResources(Resource.Type type, Predicate predicate)
+      throws UnsupportedPropertyException,
+             SystemException,
+             NoSuchResourceException,
+             NoSuchParentResourceException {
 
     ResourceProvider provider = ensureResourceProvider(type);
     if (provider != null) {
-      predicate = checkPredicate(type, null, predicate);
-      if (predicate == null) {
-        return null;
+      if (!checkProperties(type, null, predicate)) {
+        predicate = resolvePredicate(type, predicate);
+        if (predicate == null) {
+          return null;
+        }
       }
-      return provider.deleteResources(predicate);
+        return provider.deleteResources(predicate);
     }
     return null;
   }
@@ -167,28 +178,25 @@ public class ClusterControllerImpl implements ClusterController {
   // ----- helper methods ----------------------------------------------------
 
   /**
-   * Check to see if any of the property ids specified in the given request and
-   * predicate are handled by an associated property provider.  if so, then use
-   * the given predicate to obtain a new predicate that can be completely
-   * processed by an update or delete operation on a resource provider for
-   * the given resource type.  This means that the new predicate should only
-   * reference the key property ids for this type.
+   * Check to make sure that all the property ids specified in the given request and
+   * predicate are supported by the resource provider or property providers for the
+   * given type.
    *
    * @param type       the resource type
    * @param request    the request
    * @param predicate  the predicate
    *
-   * @return the given predicate if a new one is not required; a new predicate if required
-   *
-   * @throws AmbariException thrown if the new predicate can not be obtained
+   * @return true if all of the properties specified in the request and predicate are supported by
+   *         the resource provider for the given type; false if any of the properties specified in
+   *         the request and predicate are not supported by the resource provider but are supported
+   *         by a property provider for the given type.
    *
    * @throws UnsupportedPropertyException thrown if any of the properties specified in the request
    *                                      and predicate are not supported by either the resource
    *                                      provider or a property provider for the given type
    */
-  private Predicate checkPredicate(Resource.Type type, Request request, Predicate predicate)
-      throws AmbariException, UnsupportedPropertyException {
-
+  private boolean checkProperties(Resource.Type type, Request request, Predicate predicate)
+      throws UnsupportedPropertyException {
     Set<String> requestPropertyIds = request == null ? new HashSet<String>() :
         PropertyHelper.getAssociatedPropertyIds(request);
 
@@ -198,50 +206,84 @@ public class ClusterControllerImpl implements ClusterController {
 
     if (requestPropertyIds.size() > 0) {
       ResourceProvider provider = ensureResourceProvider(type);
-      requestPropertyIds.removeAll(provider.getPropertyIds());
-
-      // if any of the properties are handled by a property provider then
-      // get a new predicate based on the primary key fields
-      List<PropertyProvider> propertyProviders = ensurePropertyProviders(type);
-      for (PropertyProvider propertyProvider : propertyProviders) {
-        if (requestPropertyIds.removeAll(propertyProvider.getPropertyIds())) {
-          Set<String>  keyPropertyIds = new HashSet<String>(provider.getKeyPropertyIds().values());
-          Request          readRequest    = PropertyHelper.getReadRequest(keyPropertyIds);
-
-          Iterable<Resource> resources = getResources(type, readRequest, predicate);
-
-          PredicateBuilder pb = new PredicateBuilder();
-          PredicateBuilder.PredicateBuilderWithPredicate pbWithPredicate = null;
-
-          for (Resource resource : resources) {
-            if (pbWithPredicate != null) {
-              pb = pbWithPredicate.or();
-            }
-
-            pb              = pb.begin();
-            pbWithPredicate = null;
-
-            for (String keyPropertyId : keyPropertyIds) {
-              if (pbWithPredicate != null) {
-                pb = pbWithPredicate.and();
-              }
-              pbWithPredicate =
-                  pb.property(keyPropertyId).equals((Comparable) resource.getPropertyValue(keyPropertyId));
-            }
-            if (pbWithPredicate != null) {
-              pbWithPredicate = pbWithPredicate.end();
-            }
+      requestPropertyIds = provider.checkPropertyIds(requestPropertyIds);
+
+      if (requestPropertyIds.size() > 0) {
+        List<PropertyProvider> propertyProviders = ensurePropertyProviders(type);
+        for (PropertyProvider propertyProvider : propertyProviders) {
+          requestPropertyIds = propertyProvider.checkPropertyIds(requestPropertyIds);
+          if (requestPropertyIds.size() == 0) {
+            return false;
           }
-          return pbWithPredicate == null ? null : pbWithPredicate.toPredicate();
         }
+        throw new UnsupportedPropertyException(type, requestPropertyIds);
+      }
+    }
+    return true;
+  }
+
+  /**
+   * Check to see if any of the property ids specified in the given request and
+   * predicate are handled by an associated property provider.  if so, then use
+   * the given predicate to obtain a new predicate that can be completely
+   * processed by an update or delete operation on a resource provider for
+   * the given resource type.  This means that the new predicate should only
+   * reference the key property ids for this type.
+   *
+   * @param type       the resource type
+   * @param predicate  the predicate
+   *
+   * @return the given predicate if a new one is not required; a new predicate if required
+   *
+   * @throws UnsupportedPropertyException thrown if any of the properties specified in the request
+   *                                      and predicate are not supported by either the resource
+   *                                      provider or a property provider for the given type
+   *
+   * @throws SystemException thrown for internal exceptions
+   * @throws NoSuchResourceException if the resource that is requested doesn't exist
+   * @throws NoSuchParentResourceException if a parent resource of the requested resource doesn't exist
+   */
+  private Predicate resolvePredicate(Resource.Type type, Predicate predicate)
+    throws UnsupportedPropertyException,
+        SystemException,
+        NoSuchResourceException,
+        NoSuchParentResourceException{
+
+    ResourceProvider provider = ensureResourceProvider(type);
+
+    Set<String>  keyPropertyIds = new HashSet<String>(provider.getKeyPropertyIds().values());
+    Request      readRequest    = PropertyHelper.getReadRequest(keyPropertyIds);
+
+    Iterable<Resource> resources = getResources(type, readRequest, predicate);
+
+    PredicateBuilder pb = new PredicateBuilder();
+    PredicateBuilder.PredicateBuilderWithPredicate pbWithPredicate = null;
+
+    for (Resource resource : resources) {
+      if (pbWithPredicate != null) {
+        pb = pbWithPredicate.or();
+      }
+
+      pb              = pb.begin();
+      pbWithPredicate = null;
+
+      for (String keyPropertyId : keyPropertyIds) {
+        if (pbWithPredicate != null) {
+          pb = pbWithPredicate.and();
+        }
+        pbWithPredicate =
+            pb.property(keyPropertyId).equals((Comparable) resource.getPropertyValue(keyPropertyId));
+      }
+      if (pbWithPredicate != null) {
+        pbWithPredicate = pbWithPredicate.end();
       }
     }
-    return predicate;
+    return pbWithPredicate == null ? null : pbWithPredicate.toPredicate();
   }
 
   /**
    * Populate the given resources from the associated property providers.  This
-   * method may filter the resources based on the predicated and return a subset
+   * method may filter the resources based on the predicate and return a subset
    * of the given resources.
    *
    * @param type       the resource type
@@ -251,12 +293,12 @@ public class ClusterControllerImpl implements ClusterController {
    *
    * @return the set of resources that were successfully populated
    *
-   * @throws AmbariException thrown if the resources can not be populated
+   * @throws SystemException if unable to populate the resources
    */
   private Set<Resource> populateResources(Resource.Type type,
                                           Set<Resource> resources,
                                           Request request,
-                                          Predicate predicate) throws AmbariException{
+                                          Predicate predicate) throws SystemException {
     Set<Resource> keepers = resources;
 
     for (PropertyProvider propertyProvider : propertyProviders.get(type)) {
@@ -283,9 +325,10 @@ public class ClusterControllerImpl implements ClusterController {
       return true;
     }
     requestPropertyIds.addAll(PredicateHelper.getPropertyIds(predicate));
-    requestPropertyIds.retainAll(provider.getPropertyIds());
 
-    return !requestPropertyIds.isEmpty();
+    int size = requestPropertyIds.size();
+
+    return size > provider.checkPropertyIds(requestPropertyIds).size();
   }
 
   /**

+ 54 - 20
ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterResourceProvider.java

@@ -21,11 +21,17 @@ import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.controller.AmbariManagementController;
 import org.apache.ambari.server.controller.ClusterRequest;
 import org.apache.ambari.server.controller.ClusterResponse;
+import org.apache.ambari.server.controller.RequestStatusResponse;
+import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
+import org.apache.ambari.server.controller.spi.NoSuchResourceException;
 import org.apache.ambari.server.controller.spi.Predicate;
 import org.apache.ambari.server.controller.spi.Request;
 import org.apache.ambari.server.controller.spi.RequestStatus;
 import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException;
+import org.apache.ambari.server.controller.spi.SystemException;
 import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
+import org.apache.ambari.server.controller.utilities.PredicateHelper;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
 
 import java.util.Arrays;
@@ -45,7 +51,6 @@ class ClusterResourceProvider extends ResourceProviderImpl{
   protected static final String CLUSTER_ID_PROPERTY_ID      = PropertyHelper.getPropertyId("Clusters", "cluster_id");
   protected static final String CLUSTER_NAME_PROPERTY_ID    = PropertyHelper.getPropertyId("Clusters", "cluster_name");
   protected static final String CLUSTER_VERSION_PROPERTY_ID = PropertyHelper.getPropertyId("Clusters", "version");
-  protected static final String CLUSTER_HOSTS_PROPERTY_ID   = PropertyHelper.getPropertyId("Clusters", "hosts");
 
 
   private static Set<String> pkPropertyIds =
@@ -70,11 +75,20 @@ class ClusterResourceProvider extends ResourceProviderImpl{
 // ----- ResourceProvider ------------------------------------------------
 
   @Override
-  public RequestStatus createResources(Request request) throws AmbariException, UnsupportedPropertyException {
-
-    checkRequestProperties(Resource.Type.Cluster, request);
-    for (Map<String, Object> properties : request.getProperties()) {
-      getManagementController().createCluster(getRequest(properties));
+  public RequestStatus createResources(Request request)
+      throws SystemException,
+             UnsupportedPropertyException,
+             ResourceAlreadyExistsException,
+             NoSuchParentResourceException {
+
+    for (final Map<String, Object> properties : request.getProperties()) {
+      createResources(new Command<Void>() {
+        @Override
+        public Void invoke() throws AmbariException {
+          getManagementController().createCluster(getRequest(properties));
+          return null;
+        }
+      });
     }
     notifyCreate(Resource.Type.Cluster, request);
 
@@ -82,12 +96,19 @@ class ClusterResourceProvider extends ResourceProviderImpl{
   }
 
   @Override
-  public Set<Resource> getResources(Request request, Predicate predicate) throws AmbariException, UnsupportedPropertyException {
-    ClusterRequest clusterRequest = getRequest(getProperties(predicate));
-    Set<String> requestedIds   = PropertyHelper.getRequestPropertyIds(getPropertyIds(), request, predicate);
+  public Set<Resource> getResources(Request request, Predicate predicate)
+      throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+
+    final ClusterRequest clusterRequest = getRequest(PredicateHelper.getProperties(predicate));
+    Set<String> requestedIds = PropertyHelper.getRequestPropertyIds(getPropertyIds(), request, predicate);
 
     // TODO : handle multiple requests
-    Set<ClusterResponse> responses = getManagementController().getClusters(Collections.singleton(clusterRequest));
+    Set<ClusterResponse> responses = getResources(new Command<Set<ClusterResponse>>() {
+      @Override
+      public Set<ClusterResponse> invoke() throws AmbariException {
+        return getManagementController().getClusters(Collections.singleton(clusterRequest));
+      }
+    });
 
     Set<Resource> resources = new HashSet<Resource>();
     if (LOG.isDebugEnabled()) {
@@ -113,25 +134,38 @@ class ClusterResourceProvider extends ResourceProviderImpl{
   }
 
   @Override
-  public RequestStatus updateResources(Request request, Predicate predicate) throws AmbariException, UnsupportedPropertyException {
-    checkRequestProperties(Resource.Type.Cluster, request);
+  public RequestStatus updateResources(Request request, Predicate predicate)
+      throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+
     for (Map<String, Object> propertyMap : getPropertyMaps(request.getProperties().iterator().next(), predicate)) {
-      ClusterRequest clusterRequest = getRequest(propertyMap);
-      getManagementController().updateCluster(clusterRequest);
+      final ClusterRequest clusterRequest = getRequest(propertyMap);
+
+      modifyResources(new Command<RequestStatusResponse>() {
+        @Override
+        public RequestStatusResponse invoke() throws AmbariException {
+          return getManagementController().updateCluster(clusterRequest);
+        }
+      });
     }
     notifyUpdate(Resource.Type.Cluster, request, predicate);
-
     return getRequestStatus(null);
   }
 
   @Override
-  public RequestStatus deleteResources(Predicate predicate) throws AmbariException, UnsupportedPropertyException {
-    for (Map<String, Object> propertyMap : getPropertyMaps(null, predicate)) {
-      ClusterRequest clusterRequest = getRequest(propertyMap);
-      getManagementController().deleteCluster(clusterRequest);
+  public RequestStatus deleteResources(Predicate predicate)
+      throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+
+    for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) {
+      final ClusterRequest clusterRequest = getRequest(propertyMap);
+      modifyResources(new Command<Void>() {
+        @Override
+        public Void invoke() throws AmbariException {
+          getManagementController().deleteCluster(clusterRequest);
+          return null;
+        }
+      });
     }
     notifyDelete(Resource.Type.Cluster, predicate);
-
     return getRequestStatus(null);
   }
 

+ 57 - 26
ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ComponentResourceProvider.java

@@ -22,11 +22,7 @@ import org.apache.ambari.server.controller.AmbariManagementController;
 import org.apache.ambari.server.controller.RequestStatusResponse;
 import org.apache.ambari.server.controller.ServiceComponentRequest;
 import org.apache.ambari.server.controller.ServiceComponentResponse;
-import org.apache.ambari.server.controller.spi.Predicate;
-import org.apache.ambari.server.controller.spi.Request;
-import org.apache.ambari.server.controller.spi.RequestStatus;
-import org.apache.ambari.server.controller.spi.Resource;
-import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
+import org.apache.ambari.server.controller.spi.*;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
 
 import java.util.Arrays;
@@ -75,29 +71,49 @@ class ComponentResourceProvider extends ResourceProviderImpl{
   // ----- ResourceProvider ------------------------------------------------
 
   @Override
-  public RequestStatus createResources(Request request) throws AmbariException, UnsupportedPropertyException {
-    checkRequestProperties(Resource.Type.Component, request);
-    Set<ServiceComponentRequest> requests = new HashSet<ServiceComponentRequest>();
+  public RequestStatus createResources(Request request)
+      throws SystemException,
+             UnsupportedPropertyException,
+             ResourceAlreadyExistsException,
+             NoSuchParentResourceException {
+
+    final Set<ServiceComponentRequest> requests = new HashSet<ServiceComponentRequest>();
     for (Map<String, Object> propertyMap : request.getProperties()) {
       requests.add(getRequest(propertyMap));
     }
-    getManagementController().createComponents(requests);
+
+    createResources(new Command<Void>() {
+      @Override
+      public Void invoke() throws AmbariException {
+        getManagementController().createComponents(requests);
+        return null;
+      }
+    });
+
     notifyCreate(Resource.Type.Component, request);
 
     return getRequestStatus(null);
   }
 
   @Override
-  public Set<Resource> getResources(Request request, Predicate predicate) throws AmbariException, UnsupportedPropertyException {
-    Set<ServiceComponentRequest> requests = new HashSet<ServiceComponentRequest>();
+  public Set<Resource> getResources(Request request, Predicate predicate)
+      throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+
+    final Set<ServiceComponentRequest> requests = new HashSet<ServiceComponentRequest>();
 
-    for (Map<String, Object> propertyMap : getPropertyMaps(null, predicate)) {
+    for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) {
       requests.add(getRequest(propertyMap));
     }
 
-    Set<String>               requestedIds = PropertyHelper.getRequestPropertyIds(getPropertyIds(), request, predicate);
-    Set<ServiceComponentResponse> responses     = getManagementController().getComponents(requests);
-    Set<Resource>                 resources    = new HashSet<Resource>();
+    Set<ServiceComponentResponse> responses = getResources(new Command<Set<ServiceComponentResponse>>() {
+      @Override
+      public Set<ServiceComponentResponse> invoke() throws AmbariException {
+        return getManagementController().getComponents(requests);
+      }
+    });
+
+    Set<String>   requestedIds = PropertyHelper.getRequestPropertyIds(getPropertyIds(), request, predicate);
+    Set<Resource> resources    = new HashSet<Resource>();
 
     for (ServiceComponentResponse response : responses) {
       Resource resource = new ResourceImpl(Resource.Type.Component);
@@ -114,13 +130,13 @@ class ComponentResourceProvider extends ResourceProviderImpl{
   }
 
   @Override
-  public RequestStatus updateResources(Request request, Predicate predicate) throws AmbariException, UnsupportedPropertyException {
-    checkRequestProperties(Resource.Type.Component, request);
-    Set<ServiceComponentRequest> requests = new HashSet<ServiceComponentRequest>();
+  public RequestStatus updateResources(Request request, Predicate predicate)
+      throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+
+    final Set<ServiceComponentRequest> requests = new HashSet<ServiceComponentRequest>();
     for (Map<String, Object> propertyMap : getPropertyMaps(request.getProperties().iterator().next(), predicate)) {
       ServiceComponentRequest compRequest = getRequest(propertyMap);
-
-      Map<String, String> configMap = new HashMap<String,String>();
+      Map<String, String>     configMap   = new HashMap<String,String>();
 
       for (Map.Entry<String,Object> entry : propertyMap.entrySet()) {
         if (PropertyHelper.getPropertyCategory(entry.getKey()).equals("config")) {
@@ -133,21 +149,36 @@ class ComponentResourceProvider extends ResourceProviderImpl{
 
       requests.add(compRequest);
     }
-    RequestStatusResponse response = getManagementController().updateComponents(requests);
+
+    RequestStatusResponse response = modifyResources(new Command<RequestStatusResponse>() {
+      @Override
+      public RequestStatusResponse invoke() throws AmbariException {
+        return getManagementController().updateComponents(requests);
+      }
+    });
+
     notifyUpdate(Resource.Type.Component, request, predicate);
 
     return getRequestStatus(response);
   }
 
   @Override
-  public RequestStatus deleteResources(Predicate predicate) throws AmbariException, UnsupportedPropertyException {
-    Set<ServiceComponentRequest> requests = new HashSet<ServiceComponentRequest>();
-    for (Map<String, Object> propertyMap : getPropertyMaps(null, predicate)) {
+  public RequestStatus deleteResources(Predicate predicate)
+      throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+
+    final Set<ServiceComponentRequest> requests = new HashSet<ServiceComponentRequest>();
+    for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) {
       requests.add(getRequest(propertyMap));
     }
-    RequestStatusResponse response = getManagementController().deleteComponents(requests);
-    notifyDelete(Resource.Type.Component, predicate);
 
+    RequestStatusResponse response = modifyResources(new Command<RequestStatusResponse>() {
+      @Override
+      public RequestStatusResponse invoke() throws AmbariException {
+        return getManagementController().deleteComponents(requests);
+      }
+    });
+
+    notifyDelete(Resource.Type.Component, predicate);
     return getRequestStatus(response);
   }
 

+ 97 - 22
ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ConfigurationResourceProvider.java

@@ -1,22 +1,44 @@
 package org.apache.ambari.server.controller.internal;
 
+/**
+ * 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 org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.controller.AmbariManagementController;
 import org.apache.ambari.server.controller.ConfigurationRequest;
 import org.apache.ambari.server.controller.ConfigurationResponse;
 import org.apache.ambari.server.controller.ServiceComponentHostRequest;
+import org.apache.ambari.server.controller.spi.NoSuchParentResourceException;
+import org.apache.ambari.server.controller.spi.NoSuchResourceException;
 import org.apache.ambari.server.controller.spi.Predicate;
 import org.apache.ambari.server.controller.spi.Request;
 import org.apache.ambari.server.controller.spi.RequestStatus;
 import org.apache.ambari.server.controller.spi.Resource;
+import org.apache.ambari.server.controller.spi.ResourceAlreadyExistsException;
+import org.apache.ambari.server.controller.spi.SystemException;
 import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
+import org.apache.ambari.server.controller.utilities.PredicateHelper;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
 
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.Map;
 import java.util.Set;
 import java.util.Map.Entry;
@@ -29,9 +51,10 @@ class ConfigurationResourceProvider extends ResourceProviderImpl {
   // ----- Property ID constants ---------------------------------------------
 
   // Configurations (values are part of query strings and body post, so they don't have defined categories)
-  protected static final String CONFIGURATION_CLUSTER_NAME_PROPERTY_ID    = PropertyHelper.getPropertyId("Config", "cluster_name");
-  protected static final String CONFIGURATION_CONFIG_TYPE_PROPERTY_ID     = PropertyHelper.getPropertyId(null, "type");
-  protected static final String CONFIGURATION_CONFIG_TAG_PROPERTY_ID      = PropertyHelper.getPropertyId(null, "tag");
+  protected static final String CONFIGURATION_CLUSTER_NAME_PROPERTY_ID = PropertyHelper.getPropertyId("Config", "cluster_name");
+  // TODO : should these be Config/type and Config/tag to be consistent?
+  protected static final String CONFIGURATION_CONFIG_TYPE_PROPERTY_ID  = PropertyHelper.getPropertyId(null, "type");
+  protected static final String CONFIGURATION_CONFIG_TAG_PROPERTY_ID   = PropertyHelper.getPropertyId(null, "tag");
 
   private static final String CONFIG_HOST_NAME = PropertyHelper.getPropertyId("Config", "host_name");
   private static final String CONFIG_COMPONENT_NAME = PropertyHelper.getPropertyId("Config", "component_name");
@@ -51,44 +74,62 @@ class ConfigurationResourceProvider extends ResourceProviderImpl {
   }
 
   @Override
-  public RequestStatus createResources(Request request) throws AmbariException, UnsupportedPropertyException {
+  public RequestStatus createResources(Request request)
+      throws SystemException,
+             UnsupportedPropertyException,
+             ResourceAlreadyExistsException,
+             NoSuchParentResourceException {
+
     for (Map<String, Object> map : request.getProperties()) {
 
       String cluster = (String) map.get(CONFIGURATION_CLUSTER_NAME_PROPERTY_ID);
+      // TODO : why not CONFIGURATION_CONFIG_TYPE_PROPERTY_ID?
       String type = (String) map.get(PropertyHelper.getPropertyId("", "type"));
+      // TODO : why not CONFIGURATION_CONFIG_TAG_PROPERTY_ID?
       String tag = (String) map.get(PropertyHelper.getPropertyId("", "tag"));
+
       Map<String, String> configMap = new HashMap<String, String>();
 
-      Iterator<Map.Entry<String, Object>> it1 = map.entrySet().iterator();
-      while (it1.hasNext()) {
-        Map.Entry<String, Object> entry = it1.next();
+      for (Entry<String, Object> entry : map.entrySet()) {
         if (PropertyHelper.getPropertyCategory(entry.getKey()).equals("properties") && null != entry.getValue()) {
           configMap.put(PropertyHelper.getPropertyName(entry.getKey()), entry.getValue().toString());
         }
       }
 
-      ConfigurationRequest configRequest = new ConfigurationRequest(cluster, type, tag, configMap);
+      final ConfigurationRequest configRequest = new ConfigurationRequest(cluster, type, tag, configMap);
+
+      createResources(new Command<Void>() {
+        @Override
+        public Void invoke() throws AmbariException {
+          getManagementController().createConfiguration(configRequest);
+          return null;
+        }
+      });
 
-      getManagementController().createConfiguration(configRequest);
     }
     return getRequestStatus(null);
   }
 
   @Override
   public Set<Resource> getResources(Request request, Predicate predicate)
-      throws AmbariException, UnsupportedPropertyException {
-    Map<String, Object> map = getProperties(predicate);
+    throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+    Map<String, Object> map = PredicateHelper.getProperties(predicate);
     
     if (map.containsKey(CONFIG_HOST_NAME) && map.containsKey(CONFIG_COMPONENT_NAME)) {
-      ServiceComponentHostRequest hostComponentRequest = new ServiceComponentHostRequest(
+      final ServiceComponentHostRequest hostComponentRequest = new ServiceComponentHostRequest(
           (String) map.get(CONFIGURATION_CLUSTER_NAME_PROPERTY_ID),
           null,
           (String) map.get(CONFIG_COMPONENT_NAME),
           (String) map.get(CONFIG_HOST_NAME),
           null, null);
       
-      Map<String, String> mappints = getManagementController().getHostComponentDesiredConfigMapping(hostComponentRequest);
-      
+      Map<String, String> mappints = getResources(new Command<Map<String, String>>() {
+        @Override
+        public Map<String, String> invoke() throws AmbariException {
+          return getManagementController().getHostComponentDesiredConfigMapping(hostComponentRequest);
+        }
+      });
+
       Set<Resource> resources = new HashSet<Resource>();
       
       for (Entry<String, String> entry : mappints.entrySet()) {
@@ -110,9 +151,14 @@ class ConfigurationResourceProvider extends ResourceProviderImpl {
       
     } else {
       // TODO : handle multiple requests
-      ConfigurationRequest configRequest = getRequest(map);
+      final ConfigurationRequest configRequest = getRequest(map);
       
-      Set<ConfigurationResponse> responses = getManagementController().getConfigurations(Collections.singleton(configRequest));
+      Set<ConfigurationResponse> responses = getResources(new Command<Set<ConfigurationResponse>>() {
+        @Override
+        public Set<ConfigurationResponse> invoke() throws AmbariException {
+          return getManagementController().getConfigurations(Collections.singleton(configRequest));
+        }
+      });
 
       Set<Resource> resources = new HashSet<Resource>();
       for (ConfigurationResponse response : responses) {
@@ -142,16 +188,42 @@ class ConfigurationResourceProvider extends ResourceProviderImpl {
    */
   @Override
   public RequestStatus updateResources(Request request, Predicate predicate)
-      throws AmbariException, UnsupportedPropertyException {
-    throw new AmbariException ("Cannot update a Configuration resource.");
+      throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+    throw new UnsupportedOperationException("Cannot update a Configuration resource.");
   }
 
   /**
    * Throws an exception, as Configurations cannot be deleted.
    */
   @Override
-  public RequestStatus deleteResources(Predicate predicate) throws AmbariException, UnsupportedPropertyException {
-    throw new AmbariException ("Cannot delete a Configuration resource.");
+  public RequestStatus deleteResources(Predicate predicate) throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+    throw new UnsupportedOperationException("Cannot delete a Configuration resource.");
+  }
+
+  @Override
+  public Set<String> checkPropertyIds(Set<String> propertyIds) {
+    propertyIds = super.checkPropertyIds(propertyIds);
+
+    if (propertyIds.isEmpty()) {
+      return propertyIds;
+    }
+    Set<String> unsupportedProperties = new HashSet<String>();
+
+    for (String propertyId : propertyIds) {
+
+      // TODO : hack to allow for inconsistent property names
+      // for example, the tag property can come here as Config/tag, /tag or tag
+      if (!propertyId.equals("tag") && !propertyId.equals("type") &&
+          !propertyId.equals("/tag") && !propertyId.equals("/type")) {
+
+        String propertyCategory = PropertyHelper.getPropertyCategory(propertyId);
+
+        if (propertyCategory == null || !propertyCategory.equals("properties")) {
+          unsupportedProperties.add(propertyId);
+        }
+      }
+    }
+    return unsupportedProperties;
   }
 
   @Override
@@ -159,13 +231,16 @@ class ConfigurationResourceProvider extends ResourceProviderImpl {
     return pkPropertyIds;
   }
 
-  public static void getConfigPropertyValues(Map<String, Object> propertyMap, Map<String, String> configMap) {
+  public static Map<String, String> getConfigPropertyValues(Map<String, Object> propertyMap) {
+    Map<String, String> configMap = new HashMap<String, String>();
+
     for (Map.Entry<String,Object> entry : propertyMap.entrySet()) {
       String propertyId = entry.getKey();
       if (PropertyHelper.getPropertyCategory(propertyId).equals("config")) {
         configMap.put(PropertyHelper.getPropertyName(propertyId), (String) entry.getValue());
       }
     }
+    return configMap;
   }
 
   private ConfigurationRequest getRequest(Map<String, Object> properties) {

+ 17 - 17
ambari-server/src/main/java/org/apache/ambari/server/controller/internal/DefaultProviderModule.java

@@ -18,7 +18,6 @@
 
 package org.apache.ambari.server.controller.internal;
 
-import org.apache.ambari.server.AmbariException;
 import org.apache.ambari.server.controller.AmbariServer;
 import org.apache.ambari.server.controller.ganglia.GangliaComponentPropertyProvider;
 import org.apache.ambari.server.controller.ganglia.GangliaHostComponentPropertyProvider;
@@ -27,16 +26,10 @@ import org.apache.ambari.server.controller.ganglia.GangliaReportPropertyProvider
 import org.apache.ambari.server.controller.ganglia.GangliaHostProvider;
 import org.apache.ambari.server.controller.jmx.JMXHostProvider;
 import org.apache.ambari.server.controller.jmx.JMXPropertyProvider;
-import org.apache.ambari.server.controller.spi.Predicate;
-import org.apache.ambari.server.controller.spi.ProviderModule;
-import org.apache.ambari.server.controller.spi.Request;
-import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
+import org.apache.ambari.server.controller.spi.*;
 import org.apache.ambari.server.controller.utilities.PredicateBuilder;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
 import org.apache.ambari.server.controller.AmbariManagementController;
-import org.apache.ambari.server.controller.spi.PropertyProvider;
-import org.apache.ambari.server.controller.spi.Resource;
-import org.apache.ambari.server.controller.spi.ResourceProvider;
 
 import com.google.inject.Inject;
 import org.slf4j.Logger;
@@ -148,13 +141,13 @@ public class DefaultProviderModule implements ProviderModule, ResourceProviderOb
   // ----- JMXHostProvider ---------------------------------------------------
 
   @Override
-  public String getHostName(String clusterName, String componentName) {
+  public String getHostName(String clusterName, String componentName) throws SystemException {
     checkInit();
     return clusterHostComponentMap.get(clusterName).get(componentName);
   }
 
   @Override
-  public Map<String, String> getHostMapping(String clusterName) {
+  public Map<String, String> getHostMapping(String clusterName) throws SystemException {
     checkInit();
     return clusterHostMap.get(clusterName);
   }
@@ -163,7 +156,7 @@ public class DefaultProviderModule implements ProviderModule, ResourceProviderOb
   // ----- GangliaHostProvider -----------------------------------------------
 
   @Override
-  public String getGangliaCollectorHostName(String clusterName) {
+  public String getGangliaCollectorHostName(String clusterName) throws SystemException {
     checkInit();
     return clusterGangliaCollectorMap.get(clusterName);
   }
@@ -253,7 +246,7 @@ public class DefaultProviderModule implements ProviderModule, ResourceProviderOb
     putPropertyProviders(type, providers);
   }
 
-  private void checkInit() {
+  private void checkInit() throws SystemException{
     if (!initialized) {
       synchronized (this) {
         if (!initialized) {
@@ -272,7 +265,7 @@ public class DefaultProviderModule implements ProviderModule, ResourceProviderOb
     }
   }
 
-  private void initProviderMaps() {
+  private void initProviderMaps() throws SystemException{
     ResourceProvider provider = getResourceProvider(Resource.Type.Cluster);
     Request          request  = PropertyHelper.getReadRequest(CLUSTER_NAME_PROPERTY_ID);
 
@@ -337,14 +330,21 @@ public class DefaultProviderModule implements ProviderModule, ResourceProviderOb
           }
         }
       }
-    } catch (AmbariException e) {
+    } catch (UnsupportedPropertyException e) {
       if (LOG.isErrorEnabled()) {
-        LOG.error("Caught exception while trying to get the host mappings.", e);
+        LOG.error("Caught UnsupportedPropertyException while trying to get the host mappings.", e);
       }
-    } catch (UnsupportedPropertyException e) {
+      throw new SystemException("An exception occurred while initializing the host mappings: " + e, e);
+    } catch (NoSuchResourceException e) {
+      if (LOG.isErrorEnabled()) {
+        LOG.error("Caught NoSuchResourceException exception while trying to get the host mappings.", e);
+      }
+      throw new SystemException("An exception occurred while initializing the host mappings: " + e, e);
+    } catch (NoSuchParentResourceException e) {
       if (LOG.isErrorEnabled()) {
-        LOG.error("Caught exception while trying to get the host mappings.", e);
+        LOG.error("Caught NoSuchParentResourceException exception while trying to get the host mappings.", e);
       }
+      throw new SystemException("An exception occurred while initializing the host mappings: " + e, e);
     }
   }
 }

+ 90 - 40
ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostComponentResourceProvider.java

@@ -22,23 +22,19 @@ import org.apache.ambari.server.controller.AmbariManagementController;
 import org.apache.ambari.server.controller.RequestStatusResponse;
 import org.apache.ambari.server.controller.ServiceComponentHostRequest;
 import org.apache.ambari.server.controller.ServiceComponentHostResponse;
-import org.apache.ambari.server.controller.spi.Predicate;
-import org.apache.ambari.server.controller.spi.Request;
-import org.apache.ambari.server.controller.spi.RequestStatus;
-import org.apache.ambari.server.controller.spi.Resource;
-import org.apache.ambari.server.controller.spi.UnsupportedPropertyException;
+import org.apache.ambari.server.controller.spi.*;
 import org.apache.ambari.server.controller.utilities.PropertyHelper;
 
 import java.util.Arrays;
-import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.Map;
 import java.util.Set;
 
 /**
  * Resource provider for host component resources.
  */
-class HostComponentResourceProvider extends ResourceProviderImpl{
+class HostComponentResourceProvider extends ResourceProviderImpl {
 
   // ----- Property ID constants ---------------------------------------------
 
@@ -77,29 +73,50 @@ class HostComponentResourceProvider extends ResourceProviderImpl{
   // ----- ResourceProvider ------------------------------------------------
 
   @Override
-  public RequestStatus createResources(Request request) throws AmbariException, UnsupportedPropertyException {
-    checkRequestProperties(Resource.Type.HostComponent, request);
-    Set<ServiceComponentHostRequest> requests = new HashSet<ServiceComponentHostRequest>();
+  public RequestStatus createResources(Request request)
+      throws SystemException,
+             UnsupportedPropertyException,
+             ResourceAlreadyExistsException,
+             NoSuchParentResourceException {
+
+    final Set<ServiceComponentHostRequest> requests = new HashSet<ServiceComponentHostRequest>();
     for (Map<String, Object> propertyMap : request.getProperties()) {
       requests.add(getRequest(propertyMap));
     }
-    getManagementController().createHostComponents(requests);
+
+    createResources(new Command<Void>() {
+      @Override
+      public Void invoke() throws AmbariException {
+        getManagementController().createHostComponents(requests);
+        return null;
+      }
+    });
+
     notifyCreate(Resource.Type.HostComponent, request);
 
     return getRequestStatus(null);
   }
 
   @Override
-  public Set<Resource> getResources(Request request, Predicate predicate) throws AmbariException, UnsupportedPropertyException {
-    Set<ServiceComponentHostRequest> requests = new HashSet<ServiceComponentHostRequest>();
+  public Set<Resource> getResources(Request request, Predicate predicate)
+      throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
 
-    for (Map<String, Object> propertyMap : getPropertyMaps(null, predicate)) {
+    final Set<ServiceComponentHostRequest> requests = new HashSet<ServiceComponentHostRequest>();
+
+    for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) {
       requests.add(getRequest(propertyMap));
     }
 
-    Set<String>                   requestedIds = PropertyHelper.getRequestPropertyIds(getPropertyIds(), request, predicate);
-    Set<ServiceComponentHostResponse> responses     = getManagementController().getHostComponents(requests);
-    Set<Resource>                     resources    = new HashSet<Resource>();
+    Set<Resource> resources    = new HashSet<Resource>();
+    Set<String>   requestedIds = PropertyHelper.getRequestPropertyIds(getPropertyIds(), request, predicate);
+
+    Set<ServiceComponentHostResponse> responses = getResources(new Command<Set<ServiceComponentHostResponse>>() {
+      @Override
+      public Set<ServiceComponentHostResponse> invoke() throws AmbariException {
+        return getManagementController().getHostComponents(requests);
+      }
+    });
+
     for (ServiceComponentHostResponse response : responses) {
       Resource resource = new ResourceImpl(Resource.Type.HostComponent);
       setResourceProperty(resource, HOST_COMPONENT_CLUSTER_NAME_PROPERTY_ID, response.getClusterName(), requestedIds);
@@ -118,41 +135,66 @@ class HostComponentResourceProvider extends ResourceProviderImpl{
   }
 
   @Override
-  public RequestStatus updateResources(Request request, Predicate predicate) throws AmbariException, UnsupportedPropertyException {
-    checkRequestProperties(Resource.Type.HostComponent, request);
-    Set<ServiceComponentHostRequest> requests = new HashSet<ServiceComponentHostRequest>();
-    for (Map<String, Object> propertyMap : getPropertyMaps(request.getProperties().iterator().next(), predicate)) {
-
-      ServiceComponentHostRequest hostCompRequest = getRequest(propertyMap);
-
-      Map<String, String> configMap = new HashMap<String,String>();
-
-      ConfigurationResourceProvider.getConfigPropertyValues(propertyMap, configMap);
-
-      if (0 != configMap.size()) {
-        hostCompRequest.setConfigVersions(configMap);
+  public RequestStatus updateResources(Request request, Predicate predicate)
+        throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+    final Set<ServiceComponentHostRequest> requests = new HashSet<ServiceComponentHostRequest>();
+    RequestStatusResponse response = null;
+
+    Iterator<Map<String,Object>> iterator = request.getProperties().iterator();
+    if (iterator.hasNext()) {
+      for (Map<String, Object> propertyMap : getPropertyMaps(request.getProperties().iterator().next(), predicate)) {
+        requests.add(getRequest(propertyMap));
       }
-
-      requests.add(hostCompRequest);
+      response = modifyResources(new Command<RequestStatusResponse>() {
+        @Override
+        public RequestStatusResponse invoke() throws AmbariException {
+          return getManagementController().updateHostComponents(requests);
+        }
+      });
+
+      notifyUpdate(Resource.Type.HostComponent, request, predicate);
     }
-    RequestStatusResponse response = getManagementController().updateHostComponents(requests);
-    notifyUpdate(Resource.Type.HostComponent, request, predicate);
-
     return getRequestStatus(response);
   }
 
   @Override
-  public RequestStatus deleteResources(Predicate predicate) throws AmbariException, UnsupportedPropertyException {
-    Set<ServiceComponentHostRequest> requests = new HashSet<ServiceComponentHostRequest>();
-    for (Map<String, Object> propertyMap : getPropertyMaps(null, predicate)) {
+  public RequestStatus deleteResources(Predicate predicate)
+      throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException {
+    final Set<ServiceComponentHostRequest> requests = new HashSet<ServiceComponentHostRequest>();
+    for (Map<String, Object> propertyMap : getPropertyMaps(predicate)) {
       requests.add(getRequest(propertyMap));
     }
-    RequestStatusResponse response = getManagementController().deleteHostComponents(requests);
+    RequestStatusResponse response = modifyResources(new Command<RequestStatusResponse>() {
+      @Override
+      public RequestStatusResponse invoke() throws AmbariException {
+        return getManagementController().deleteHostComponents(requests);
+      }
+    });
+
     notifyDelete(Resource.Type.HostComponent, predicate);
 
     return getRequestStatus(response);
   }
 
+  @Override
+  public Set<String> checkPropertyIds(Set<String> propertyIds) {
+    propertyIds = super.checkPropertyIds(propertyIds);
+
+    if (propertyIds.isEmpty()) {
+      return propertyIds;
+    }
+    Set<String> unsupportedProperties = new HashSet<String>();
+
+    for (String propertyId : propertyIds) {
+      String propertyCategory = PropertyHelper.getPropertyCategory(propertyId);
+      if (propertyCategory == null || !propertyCategory.equals("config")) {
+        unsupportedProperties.add(propertyId);
+      }
+    }
+    return unsupportedProperties;
+  }
+
+
   // ----- utility methods -------------------------------------------------
 
   @Override
@@ -168,12 +210,20 @@ class HostComponentResourceProvider extends ResourceProviderImpl{
    * @return the component request object
    */
   private ServiceComponentHostRequest getRequest(Map<String, Object> properties) {
-    return new ServiceComponentHostRequest(
+    ServiceComponentHostRequest serviceComponentHostRequest = new ServiceComponentHostRequest(
         (String) properties.get(HOST_COMPONENT_CLUSTER_NAME_PROPERTY_ID),
         (String) properties.get(HOST_COMPONENT_SERVICE_NAME_PROPERTY_ID),
         (String) properties.get(HOST_COMPONENT_COMPONENT_NAME_PROPERTY_ID),
         (String) properties.get(HOST_COMPONENT_HOST_NAME_PROPERTY_ID),
         null,
         (String) properties.get(HOST_COMPONENT_STATE_PROPERTY_ID));
+
+    Map<String, String> configMappings =
+        ConfigurationResourceProvider.getConfigPropertyValues(properties);
+
+    if (configMappings.size() > 0) {
+      serviceComponentHostRequest.setConfigVersions(configMappings);
+    }
+    return serviceComponentHostRequest;
   }
 }

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä