You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by ja...@apache.org on 2014/07/21 22:48:59 UTC

[4/4] git commit: AMBARI-6519. View: Capacity Scheduler view. (jaimin)

AMBARI-6519. View: Capacity Scheduler view. (jaimin)


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

Branch: refs/heads/trunk
Commit: bb0116c3ce165a5a86cd287e058a2c8ebcb5908d
Parents: e40b18a
Author: Jaimin Jetly <ja...@hortonworks.com>
Authored: Mon Jul 21 13:48:21 2014 -0700
Committer: Jaimin Jetly <ja...@hortonworks.com>
Committed: Mon Jul 21 13:48:38 2014 -0700

----------------------------------------------------------------------
 contrib/views/capacity-scheduler/pom.xml        | 230 +++++++++
 .../src/assembly/assembly.xml                   |  26 +
 .../CapacitySchedulerService.java               |  50 ++
 .../capacityscheduler/ConfigurationService.java | 276 ++++++++++
 .../view/capacityscheduler/HelpService.java     |  70 +++
 .../view/capacityscheduler/proxy/Proxy.java     | 120 +++++
 .../capacityscheduler/proxy/RequestBuilder.java | 157 ++++++
 .../proxy/ResponseTranslator.java               |  88 ++++
 .../MisconfigurationFormattedException.java     |  46 ++
 .../utils/ServiceFormattedException.java        |  54 ++
 .../src/main/resources/ui/.gitignore            |  34 ++
 .../src/main/resources/ui/app/adapters.js       | 513 +++++++++++++++++++
 .../src/main/resources/ui/app/app.js            |  19 +
 .../ui/app/assets/data/capacity-scheduler.json  |  90 ++++
 .../resources/ui/app/assets/data/cs-tag.json    |  13 +
 .../ui/app/assets/data/refreshqueues.json       |   7 +
 .../ui/app/assets/data/resourcemanager.json     |  18 +
 .../assets/data/scheduler-configuration.json    |  90 ++++
 .../ui/app/assets/data/view-instance.json       |  15 +
 .../ui/app/assets/fonts/fontawesome-webfont.svg | 399 +++++++++++++++
 .../src/main/resources/ui/app/assets/index.html |  48 ++
 .../src/main/resources/ui/app/components.js     |  27 +
 .../resources/ui/app/components/capacityBar.js  |  42 ++
 .../ui/app/components/capacityInput.js          |  94 ++++
 .../ui/app/components/confirmDelete.js          |  87 ++++
 .../resources/ui/app/components/escapeAcl.js    |  48 ++
 .../resources/ui/app/components/pathInput.js    |  61 +++
 .../ui/app/components/queueListItem.js          |  42 ++
 .../resources/ui/app/components/radioButton.js  |  46 ++
 .../ui/app/components/totalCapacity.js          |  98 ++++
 .../ui/app/components/userGroupInput.js         |  44 ++
 .../src/main/resources/ui/app/controllers.js    |  21 +
 .../main/resources/ui/app/controllers/queue.js  | 186 +++++++
 .../main/resources/ui/app/controllers/queues.js | 154 ++++++
 .../main/resources/ui/app/controllers/trace.js  |  26 +
 .../src/main/resources/ui/app/initialize.js     |  40 ++
 .../src/main/resources/ui/app/models.js         |  19 +
 .../src/main/resources/ui/app/models/queue.js   |  64 +++
 .../src/main/resources/ui/app/router.js         | 122 +++++
 .../resources/ui/app/styles/application.less    | 238 +++++++++
 .../src/main/resources/ui/app/templates.js      |  36 ++
 .../ui/app/templates/capacityEditForm.hbs       |  34 ++
 .../ui/app/templates/components/capacityBar.hbs |  35 ++
 .../ui/app/templates/components/pathInput.hbs   |  29 ++
 .../app/templates/components/queueListItem.hbs  |  60 +++
 .../app/templates/components/totalCapacity.hbs  |  72 +++
 .../app/templates/components/userGroupInput.hbs |  37 ++
 .../main/resources/ui/app/templates/error.hbs   |  35 ++
 .../main/resources/ui/app/templates/loading.hbs |  19 +
 .../main/resources/ui/app/templates/queue.hbs   | 229 +++++++++
 .../main/resources/ui/app/templates/queues.hbs  |  85 +++
 .../resources/ui/app/templates/queues/index.hbs |  20 +
 .../ui/app/templates/schedulerPanel.hbs         |  59 +++
 .../main/resources/ui/app/templates/trace.hbs   |  21 +
 .../src/main/resources/ui/bower.json            |  32 ++
 .../src/main/resources/ui/config.coffee         |  72 +++
 .../ui/generators/collection/collection.js.hbs  |  23 +
 .../ui/generators/collection/generator.json     |   9 +
 .../ui/generators/component/component.js.hbs    |  23 +
 .../ui/generators/component/generator.json      |   9 +
 .../ui/generators/controller/controller.js.hbs  |  23 +
 .../ui/generators/controller/generator.json     |   9 +
 .../ui/generators/model/generator.json          |   9 +
 .../resources/ui/generators/model/model.js.hbs  |  23 +
 .../ui/generators/route/generator.json          |   9 +
 .../resources/ui/generators/route/route.js.hbs  |  25 +
 .../ui/generators/template/generator.json       |   9 +
 .../ui/generators/template/template.hbs.hbs     |  18 +
 .../resources/ui/generators/view/generator.json |   9 +
 .../resources/ui/generators/view/view.js.hbs    |  23 +
 .../src/main/resources/ui/package.json          |  37 ++
 .../src/main/resources/ui/test/spec.coffee      |  17 +
 .../src/main/resources/view.xml                 |  49 ++
 contrib/views/pom.xml                           |   1 +
 74 files changed, 5022 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/bb0116c3/contrib/views/capacity-scheduler/pom.xml
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/pom.xml b/contrib/views/capacity-scheduler/pom.xml
new file mode 100644
index 0000000..225acb8
--- /dev/null
+++ b/contrib/views/capacity-scheduler/pom.xml
@@ -0,0 +1,230 @@
+<!--
+   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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>org.apache.ambari.view</groupId>
+    <artifactId>capacity-scheduler</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <name>Capacity Scheduler</name>
+
+    <parent>
+        <groupId>org.apache.ambari.views</groupId>
+        <artifactId>ambari-contrib-views</artifactId>
+        <version>0.1.0-SNAPSHOT</version>
+    </parent>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.google.inject</groupId>
+            <artifactId>guice</artifactId>
+            <version>4.0-beta</version> <!-- version -->
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jersey.containers</groupId>
+            <artifactId>jersey-container-servlet</artifactId>
+            <version>2.6</version>  <!-- version -->
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <version>1.7.5</version>
+        </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.4</version>
+        </dependency>
+        <dependency>
+            <groupId>commons-lang</groupId>
+            <artifactId>commons-lang</artifactId>
+            <version>2.2</version>
+        </dependency>
+        <dependency>
+            <groupId>com.googlecode.json-simple</groupId>
+            <artifactId>json-simple</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-codec</groupId>
+            <artifactId>commons-codec</artifactId>
+            <version>1.9</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.ambari</groupId>
+            <artifactId>ambari-views</artifactId>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+    <properties>
+      <ui.directory>${basedir}/src/main/resources/ui</ui.directory>
+    </properties>
+
+    <build>
+    <plugins>
+      <plugin>
+        <groupId>com.github.eirslett</groupId>
+        <artifactId>frontend-maven-plugin</artifactId>
+        <version>0.0.14</version>
+        <configuration>
+            <workingDirectory>src/main/resources/ui</workingDirectory>
+        </configuration>
+
+        <executions>
+          <execution>
+            <id>install node and npm</id>
+            <goals>
+                <goal>install-node-and-npm</goal>
+            </goals>
+            <!-- optional: default phase is "generate-resources" -->
+            <phase>generate-resources</phase>
+            <configuration>
+                <nodeVersion>v0.10.26</nodeVersion>
+                <npmVersion>1.4.3</npmVersion>
+            </configuration>
+          </execution>
+          <execution>
+          <id>npm install</id>
+            <goals>
+              <goal>npm</goal>
+            </goals>
+
+            <phase>generate-resources</phase>
+
+            <configuration>
+                <arguments>install --unsafe-perm --registry=http://registry.npmjs.eu</arguments>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <artifactId>exec-maven-plugin</artifactId>
+        <groupId>org.codehaus.mojo</groupId>
+        <version>1.2.1</version>
+        <executions>
+            <execution>
+            <id>Brunch build</id>
+            <phase>generate-resources</phase>
+            <goals>
+              <goal>exec</goal>
+            </goals>
+            <configuration>
+              <workingDirectory>${basedir}/src/main/resources/ui</workingDirectory>
+              <executable>node/node</executable>
+              <arguments>
+                <argument>node_modules/.bin/brunch</argument>
+                <argument>build</argument>
+                <argument>--production</argument>
+              </arguments>
+            </configuration>
+            </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <artifactId>maven-dependency-plugin</artifactId>
+        <executions>
+            <execution>
+                <phase>generate-resources</phase>
+                <goals>
+                    <goal>copy-dependencies</goal>
+                </goals>
+                <configuration>
+                    <outputDirectory>${project.build.directory}/lib</outputDirectory>
+                    <includeScope>runtime</includeScope>
+                </configuration>
+            </execution>
+        </executions>
+      </plugin>
+    </plugins>
+    <resources>
+        <resource>
+        <directory>src/main/resources/ui/public</directory>
+        <filtering>false</filtering>
+        </resource>
+
+        <resource>
+        <directory>src/main/resources/</directory>
+        <filtering>false</filtering>
+        <includes>
+            <include>view.xml</include>
+        </includes>
+        </resource>
+        <resource>
+            <targetPath>WEB-INF/lib</targetPath>
+            <filtering>false</filtering>
+            <directory>target/lib</directory>
+        </resource>
+    </resources>
+    <pluginManagement>
+        <plugins>
+        <!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
+        <plugin>
+            <groupId>org.eclipse.m2e</groupId>
+            <artifactId>lifecycle-mapping</artifactId>
+            <version>1.0.0</version>
+            <configuration>
+            <lifecycleMappingMetadata>
+                <pluginExecutions>
+                <pluginExecution>
+                    <pluginExecutionFilter>
+                    <groupId>
+                        org.codehaus.mojo
+                    </groupId>
+                    <artifactId>
+                        exec-maven-plugin
+                    </artifactId>
+                    <versionRange>
+                        [1.2.1,)
+                    </versionRange>
+                    <goals>
+                        <goal>exec</goal>
+                    </goals>
+                    </pluginExecutionFilter>
+                    <action>
+                    <ignore></ignore>
+                    </action>
+                </pluginExecution>
+                <pluginExecution>
+                    <pluginExecutionFilter>
+                    <groupId>
+                        com.github.eirslett
+                    </groupId>
+                    <artifactId>
+                        frontend-maven-plugin
+                    </artifactId>
+                    <versionRange>
+                        [0.0.14,)
+                    </versionRange>
+                    <goals>
+                        <goal>
+                        install-node-and-npm
+                        </goal>
+                        <goal>npm</goal>
+                    </goals>
+                    </pluginExecutionFilter>
+                    <action>
+                    <ignore></ignore>
+                    </action>
+                </pluginExecution>
+                </pluginExecutions>
+            </lifecycleMappingMetadata>
+            </configuration>
+        </plugin>
+        </plugins>
+    </pluginManagement>
+    </build>
+</project>

http://git-wip-us.apache.org/repos/asf/ambari/blob/bb0116c3/contrib/views/capacity-scheduler/src/assembly/assembly.xml
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/assembly/assembly.xml b/contrib/views/capacity-scheduler/src/assembly/assembly.xml
new file mode 100644
index 0000000..afdcc37
--- /dev/null
+++ b/contrib/views/capacity-scheduler/src/assembly/assembly.xml
@@ -0,0 +1,26 @@
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<assembly
+	xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
+	<containerDescriptorHandlers>
+		<containerDescriptorHandler>
+			<handlerName>metaInf-services</handlerName>
+		</containerDescriptorHandler>
+	</containerDescriptorHandlers>	
+</assembly>

http://git-wip-us.apache.org/repos/asf/ambari/blob/bb0116c3/contrib/views/capacity-scheduler/src/main/java/org/apache/ambari/view/capacityscheduler/CapacitySchedulerService.java
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/java/org/apache/ambari/view/capacityscheduler/CapacitySchedulerService.java b/contrib/views/capacity-scheduler/src/main/java/org/apache/ambari/view/capacityscheduler/CapacitySchedulerService.java
new file mode 100644
index 0000000..ae73f4a
--- /dev/null
+++ b/contrib/views/capacity-scheduler/src/main/java/org/apache/ambari/view/capacityscheduler/CapacitySchedulerService.java
@@ -0,0 +1,50 @@
+/**
+ * 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.view.capacityscheduler;
+
+import javax.ws.rs.Path;
+import org.apache.ambari.view.ViewContext;
+import com.google.inject.Inject;
+
+/**
+ * Root capacity-scheduler service
+ */
+public class CapacitySchedulerService {
+
+  @Inject
+  ViewContext context;
+
+  /**
+   * @see org.apache.ambari.view.capacityscheduler.HelpService
+   * @return service
+   */
+  @Path("/help")
+  public HelpService help() {
+    return new HelpService(context);
+  }
+
+  /**
+   * @see org.apache.ambari.view.capacityscheduler.ConfigurationService
+   * @return service
+   */
+  @Path("/configuration")
+  public ConfigurationService configuration() {
+    return new ConfigurationService(context);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/bb0116c3/contrib/views/capacity-scheduler/src/main/java/org/apache/ambari/view/capacityscheduler/ConfigurationService.java
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/java/org/apache/ambari/view/capacityscheduler/ConfigurationService.java b/contrib/views/capacity-scheduler/src/main/java/org/apache/ambari/view/capacityscheduler/ConfigurationService.java
new file mode 100644
index 0000000..02259d8
--- /dev/null
+++ b/contrib/views/capacity-scheduler/src/main/java/org/apache/ambari/view/capacityscheduler/ConfigurationService.java
@@ -0,0 +1,276 @@
+/**
+ * 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.view.capacityscheduler;
+
+import org.apache.ambari.view.ViewContext;
+import org.apache.ambari.view.capacityscheduler.utils.MisconfigurationFormattedException;
+import org.apache.ambari.view.capacityscheduler.proxy.Proxy;
+import org.apache.ambari.view.capacityscheduler.utils.ServiceFormattedException;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.json.simple.JSONValue;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.*;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.HashMap;
+
+/**
+ * Help service
+ */
+public class ConfigurationService {
+
+  private static final Logger LOG = LoggerFactory.getLogger(ConfigurationService.class);
+  private final Proxy proxy;
+  private final String baseUrl;
+
+  private ViewContext context;
+  private final String refreshRMRequestData =
+      "{\n" +
+      "  \"RequestInfo\" : {\n" +
+      "    \"command\" : \"REFRESHQUEUES\",\n" +
+      "    \"context\" : \"Refresh YARN Capacity Scheduler\"\n" +
+      "  },\n" +
+      "  \"Requests/resource_filters\": [{\n" +
+      "    \"service_name\" : \"YARN\",\n" +
+      "    \"component_name\" : \"RESOURCEMANAGER\",\n" +
+      "    \"hosts\" : \"%s\"\n" +
+      "  }]\n" +
+      "}";
+  private final String restartRMRequestData = "{\"RequestInfo\": {\n" +
+      "    \"command\":\"RESTART\",\n" +
+      "    \"context\":\"Restart ResourceManager\",\n" +
+      "    \"operation_level\": {\n" +
+      "        \"level\":\"HOST_COMPONENT\",\n" +
+      "        \"cluster_name\":\"MyCluster\",\n" +
+      "        \"host_name\":\"%s\",\n" +
+      "        \"service_name\":\"YARN\",\n" +
+      "        \"hostcomponent_name\":\"RESOURCEMANAGER\"\n" +
+      "        }\n" +
+      "    },\n" +
+      "    \"Requests/resource_filters\": [\n" +
+      "        {\n" +
+      "            \"service_name\":\"YARN\",\n" +
+      "            \"component_name\":\"RESOURCEMANAGER\",\n" +
+      "            \"hosts\":\"%s\"\n" +
+      "        }\n" +
+      "    ]\n" +
+      "}\n";
+
+  /**
+   * Constructor
+   * @param context View Context instance
+   */
+  public ConfigurationService(ViewContext context) {
+    this.context = context;
+
+    proxy = new Proxy(context.getURLStreamProvider());
+    proxy.setUseAuthorization(true);
+    proxy.setUsername(context.getProperties().get("ambari.server.username"));
+    proxy.setPassword(context.getProperties().get("ambari.server.password"));
+
+    HashMap<String, String> customHeaders = new HashMap<String, String>();
+    customHeaders.put("X-Requested-By", "capacity-scheduler-app");
+    proxy.setCustomHeaders(customHeaders);
+
+    baseUrl = context.getProperties().get("ambari.server.url");
+  }
+
+  // ================================================================================
+  // Configuration Reading
+  // ================================================================================
+
+  private final String versionTagUrl = "%s?fields=Clusters/desired_configs/capacity-scheduler";
+  private final String configurationUrl = "%%s/configurations?type=capacity-scheduler&tag=%s";
+  private final String rmHostUrl = "%s/services/YARN/components/RESOURCEMANAGER?fields=host_components/host_name";
+
+  /**
+   * Get capacity scheduler configuration
+   * @return scheduler configuration
+   */
+  @GET
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response readConfiguration() {
+    Response response = null;
+    try {
+      validateConfig();
+      String versionTag = getVersionTag();
+      JSONObject configurations = getConfigurationFromAmbari(versionTag);
+      response = Response.ok(configurations).build();
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+
+    return response;
+  }
+
+  private void validateConfig() {
+    String hostname = context.getProperties().get("ambari.server.url");
+    if (hostname == null)
+      throw new MisconfigurationFormattedException("ambari.server.url");
+
+    String username = context.getProperties().get("ambari.server.username");
+    if (username == null)
+      throw new MisconfigurationFormattedException("ambari.server.username");
+
+    String password = context.getProperties().get("ambari.server.password");
+    if (password == null)
+      throw new MisconfigurationFormattedException("ambari.server.password");
+  }
+
+  private JSONObject getConfigurationFromAmbari(String versionTag) {
+    String urlTemplate = String.format(configurationUrl, versionTag);
+    String url = String.format(urlTemplate, baseUrl);
+    return proxy.request(url).get().asJSON();
+  }
+
+  private String getVersionTag() {
+    JSONObject json = getDesiredConfigs();
+    JSONObject clusters = (JSONObject) json.get("Clusters");
+    JSONObject configs = (JSONObject) clusters.get("desired_configs");
+    JSONObject scheduler = (JSONObject) configs.get("capacity-scheduler");
+    return (String) scheduler.get("tag");
+  }
+
+  private String getClusterName() {
+    JSONObject json = getDesiredConfigs();
+    JSONObject clusters = (JSONObject) json.get("Clusters");
+    return (String) clusters.get("cluster_name");
+  }
+
+  private JSONObject getDesiredConfigs() {
+    String url = String.format(versionTagUrl, baseUrl);
+    return proxy.request(url).get().asJSON();
+  }
+
+  // ================================================================================
+  // Configuration Writing
+  // ================================================================================
+  /**
+   * Set capacity scheduler configuration
+   * @return http response
+   */
+  @PUT
+  @Consumes(MediaType.APPLICATION_JSON)
+  @Produces(MediaType.APPLICATION_JSON)
+  public Response writeConfiguration(JSONObject request) {
+    try {
+      validateConfig();
+
+      proxy.request(baseUrl).
+            setData(makeConfigUpdateData(request)).
+            put();
+
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+
+    return readConfiguration();
+  }
+
+  /**
+   * Set capacity scheduler configuration and refresh RM
+   * @return http response
+   */
+  @PUT
+  @Consumes(MediaType.APPLICATION_JSON)
+  @Produces(MediaType.APPLICATION_JSON)
+  @Path("/saveAndRefresh")
+  public Response writeAndRefreshConfiguration(JSONObject request) {
+    try {
+
+      writeConfiguration(request);
+
+      String rmHost = getRMHost();
+      JSONObject data = (JSONObject) JSONValue.parse(String.format(refreshRMRequestData, rmHost));
+      proxy.request(baseUrl + "/requests/").
+          setData(data).
+          post();
+
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+    return readConfiguration();
+  }
+
+  /**
+   * Set capacity scheduler configuration and restart RM
+   * @return http response
+   */
+  @PUT
+  @Consumes(MediaType.APPLICATION_JSON)
+  @Produces(MediaType.APPLICATION_JSON)
+  @Path("/saveAndRestart")
+  public Response writeAndRestartConfiguration(JSONObject request) {
+    try {
+
+      writeConfiguration(request);
+
+      String rmHost = getRMHost();
+      JSONObject data = (JSONObject) JSONValue.parse(String.format(restartRMRequestData, rmHost, rmHost));
+      proxy.request(baseUrl + "/requests/").
+          setData(data).
+          post();
+
+    } catch (WebApplicationException ex) {
+      throw ex;
+    } catch (Exception ex) {
+      throw new ServiceFormattedException(ex.getMessage(), ex);
+    }
+    return readConfiguration();
+  }
+
+  private String getRMHost() {
+    String rmHost = null;
+    JSONObject rmData = proxy.request(String.format(rmHostUrl, baseUrl)).get().asJSON();
+    JSONArray components = (JSONArray) rmData.get("host_components");
+    for(Object component : components) {
+      JSONObject roles = (JSONObject) ((JSONObject) component).get("HostRoles");
+      if (roles.get("component_name").equals("RESOURCEMANAGER")) {
+        rmHost = (String) roles.get("host_name");
+        break;
+      }
+    }
+    if (rmHost == null)
+      throw new ServiceFormattedException("Can't retrieve Resource Manager Host");
+    return rmHost;
+  }
+
+  private JSONObject makeConfigUpdateData(JSONObject request) {
+    JSONObject desiredConfigs = (JSONObject) request.clone();
+    desiredConfigs.put("type", "capacity-scheduler");
+    desiredConfigs.put("tag", "version" + String.valueOf(System.currentTimeMillis()));
+
+    JSONObject clusters = new JSONObject();
+    clusters.put("desired_configs", desiredConfigs);
+
+    JSONObject data = new JSONObject();
+    data.put("Clusters", clusters);
+    return data;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/bb0116c3/contrib/views/capacity-scheduler/src/main/java/org/apache/ambari/view/capacityscheduler/HelpService.java
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/java/org/apache/ambari/view/capacityscheduler/HelpService.java b/contrib/views/capacity-scheduler/src/main/java/org/apache/ambari/view/capacityscheduler/HelpService.java
new file mode 100644
index 0000000..64ce2e9
--- /dev/null
+++ b/contrib/views/capacity-scheduler/src/main/java/org/apache/ambari/view/capacityscheduler/HelpService.java
@@ -0,0 +1,70 @@
+/**
+ * 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.view.capacityscheduler;
+
+import org.apache.ambari.view.ViewContext;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Scheduler configuration service
+ */
+public class HelpService {
+
+  private static final Logger logger = LoggerFactory.getLogger(HelpService.class);
+  private ViewContext context;
+
+  /**
+   * Constructor
+   * @param context View Context instance
+   */
+  public HelpService(ViewContext context) {
+    this.context = context;
+  }
+
+  /**
+   * Version
+   * @return version
+   */
+  @GET
+  @Path("/version")
+  @Produces(MediaType.TEXT_PLAIN)
+  public Response version() {
+    return Response.ok("0.0.1-SNAPSHOT").build();
+  }
+
+  /**
+   * Description
+   * @return description
+   */
+  @GET
+  @Path("/description")
+  @Produces(MediaType.TEXT_PLAIN)
+  public Response description() {
+    return Response.ok("Application to manage YARN Capacity Scheduler").build();
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/bb0116c3/contrib/views/capacity-scheduler/src/main/java/org/apache/ambari/view/capacityscheduler/proxy/Proxy.java
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/java/org/apache/ambari/view/capacityscheduler/proxy/Proxy.java b/contrib/views/capacity-scheduler/src/main/java/org/apache/ambari/view/capacityscheduler/proxy/Proxy.java
new file mode 100644
index 0000000..c026b41
--- /dev/null
+++ b/contrib/views/capacity-scheduler/src/main/java/org/apache/ambari/view/capacityscheduler/proxy/Proxy.java
@@ -0,0 +1,120 @@
+/**
+ * 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.view.capacityscheduler.proxy;
+
+import org.apache.ambari.view.URLStreamProvider;
+import org.apache.ambari.view.capacityscheduler.utils.ServiceFormattedException;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.io.IOUtils;
+import org.json.simple.JSONObject;
+import org.json.simple.JSONValue;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Proxy with ability to make authorized request
+ * with simple authorization headers
+ */
+public class Proxy {
+  private static final Logger LOG = LoggerFactory.getLogger(Proxy.class);
+
+  private URLStreamProvider urlStreamProvider;
+  private boolean useAuthorization = false;
+  private String username;
+  private String password;
+  private Map<String, String> customHeaders;
+
+  /**
+   * Constructor
+   * @param urlStreamProvider url stream provider
+   */
+  public Proxy(URLStreamProvider urlStreamProvider) {
+    this.urlStreamProvider = urlStreamProvider;
+  }
+
+  /**
+   * Create RequestBuilder object with
+   * initialized proxy options
+   * @param url url
+   * @return RequestBuilder instance
+   */
+  public RequestBuilder request(String url) {
+    return new RequestBuilder(urlStreamProvider, url).
+                  setHeaders(makeHeaders());
+  }
+
+  private HashMap<String, String> makeHeaders() {
+    HashMap<String, String> headers = new HashMap<String, String>();
+    headers.putAll(customHeaders);
+
+    if (isUseAuthorization()) {
+      String authString = username + ":" + password;
+      byte[] authEncBytes = Base64.encodeBase64(authString.getBytes());
+      String authStringEnc = new String(authEncBytes);
+
+      headers.put("Authorization", "Basic " + authStringEnc);
+    }
+    return headers;
+  }
+
+  public boolean isUseAuthorization() {
+    return useAuthorization;
+  }
+
+  public void setUseAuthorization(boolean useAuthorization) {
+    this.useAuthorization = useAuthorization;
+  }
+
+  public String getUsername() {
+    return username;
+  }
+
+  public void setUsername(String username) {
+    this.username = username;
+  }
+
+  public String getPassword() {
+    return password;
+  }
+
+  public void setPassword(String password) {
+    this.password = password;
+  }
+
+  public URLStreamProvider getUrlStreamProvider() {
+    return urlStreamProvider;
+  }
+
+  public void setUrlStreamProvider(URLStreamProvider urlStreamProvider) {
+    this.urlStreamProvider = urlStreamProvider;
+  }
+
+  public Map<String, String> getCustomHeaders() {
+    return customHeaders;
+  }
+
+  public void setCustomHeaders(Map<String, String> customHeaders) {
+    this.customHeaders = customHeaders;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/bb0116c3/contrib/views/capacity-scheduler/src/main/java/org/apache/ambari/view/capacityscheduler/proxy/RequestBuilder.java
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/java/org/apache/ambari/view/capacityscheduler/proxy/RequestBuilder.java b/contrib/views/capacity-scheduler/src/main/java/org/apache/ambari/view/capacityscheduler/proxy/RequestBuilder.java
new file mode 100644
index 0000000..420cb35
--- /dev/null
+++ b/contrib/views/capacity-scheduler/src/main/java/org/apache/ambari/view/capacityscheduler/proxy/RequestBuilder.java
@@ -0,0 +1,157 @@
+/**
+ * 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.view.capacityscheduler.proxy;
+
+import jersey.repackaged.com.google.common.collect.ImmutableMap;
+import org.apache.ambari.view.URLStreamProvider;
+import org.apache.ambari.view.capacityscheduler.utils.ServiceFormattedException;
+import org.json.simple.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+
+/**
+ * Request builder with fluent interface
+ */
+public class RequestBuilder {
+  private static final Logger LOG = LoggerFactory.getLogger(RequestBuilder.class);
+
+  //request options
+  private String url = null;
+  private String method = null;
+  private String data = null;
+
+  private HashMap<String, String> headers = null;
+
+  private URLStreamProvider urlStreamProvider;
+
+  /**
+   * Constructor for RequestBuilder
+   * @param urlStreamProvider url stream provider
+   * @param url url
+   */
+  public RequestBuilder(URLStreamProvider urlStreamProvider, String url) {
+    this.urlStreamProvider = urlStreamProvider;
+    this.url = url;
+  }
+
+  /**
+   * Shortcut for making GET request
+   * @return ResponseTranslator object that encapsulates InputStream
+   */
+  public ResponseTranslator get() {
+    setMethod("GET");
+    return doRequest();
+  }
+
+  /**
+   * Shortcut for making PUT request
+   * @return ResponseTranslator object that encapsulates InputStream
+   */
+  public ResponseTranslator put() {
+    setMethod("PUT");
+    return doRequest();
+  }
+
+  /**
+   * Shortcut for making POST request
+   * @return ResponseTranslator object that encapsulates InputStream
+   */
+  public ResponseTranslator post() {
+    setMethod("POST");
+    return doRequest();
+  }
+
+  /**
+   * Shortcut for making DELETE request
+   * @return ResponseTranslator object that encapsulates InputStream
+   */
+  public ResponseTranslator delete() {
+    setMethod("DELETE");
+    return doRequest();
+  }
+
+  /**
+   * Make request
+   * @return ResponseTranslator object that encapsulates InputStream
+   */
+  public ResponseTranslator doRequest() {
+    LOG.debug(String.format("%s Request to %s", method, url));
+    InputStream inputStream = null;
+    try {
+      inputStream = urlStreamProvider.readFrom(url, method, data, headers);
+    } catch (IOException e) {
+      throw new ServiceFormattedException(e.getMessage(), e);
+    }
+    return new ResponseTranslator(inputStream);
+  }
+
+  public String getUrl() {
+    return url;
+  }
+
+  public RequestBuilder setUrl(String url) {
+    this.url = url;
+    return this;
+  }
+
+  public String getMethod() {
+    return method;
+  }
+
+  public RequestBuilder setMethod(String method) {
+    this.method = method;
+    return this;
+  }
+
+  public String getData() {
+    return data;
+  }
+
+  public RequestBuilder setData(String data) {
+    this.data = data;
+    return this;
+  }
+
+  public RequestBuilder setData(JSONObject data) {
+    this.data = data.toString();
+    return this;
+  }
+
+  public HashMap<String, String> getHeaders() {
+    return headers;
+  }
+
+  public RequestBuilder setHeaders(HashMap<String, String> headers) {
+    this.headers = headers;
+    return this;
+  }
+
+  public URLStreamProvider getUrlStreamProvider() {
+    return urlStreamProvider;
+  }
+
+  public RequestBuilder setUrlStreamProvider(URLStreamProvider urlStreamProvider) {
+    this.urlStreamProvider = urlStreamProvider;
+    return this;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/bb0116c3/contrib/views/capacity-scheduler/src/main/java/org/apache/ambari/view/capacityscheduler/proxy/ResponseTranslator.java
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/java/org/apache/ambari/view/capacityscheduler/proxy/ResponseTranslator.java b/contrib/views/capacity-scheduler/src/main/java/org/apache/ambari/view/capacityscheduler/proxy/ResponseTranslator.java
new file mode 100644
index 0000000..f2eca3c
--- /dev/null
+++ b/contrib/views/capacity-scheduler/src/main/java/org/apache/ambari/view/capacityscheduler/proxy/ResponseTranslator.java
@@ -0,0 +1,88 @@
+/**
+ * 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.view.capacityscheduler.proxy;
+
+import org.apache.ambari.view.capacityscheduler.utils.ServiceFormattedException;
+import org.apache.commons.io.IOUtils;
+import org.json.simple.JSONObject;
+import org.json.simple.JSONValue;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Response translator encapsulates InputStream
+ * and able to convert it to different data types
+ */
+public class ResponseTranslator {
+  private static final Logger LOG = LoggerFactory.getLogger(RequestBuilder.class);
+
+  private InputStream inputStream;
+
+  /**
+   * Constructor for ResponseTranslator
+   * @param inputStream InputStream instance
+   */
+  public ResponseTranslator(InputStream inputStream) {
+    this.inputStream = inputStream;
+  }
+
+  /**
+   * Get InputStream of response from server for manual processing
+   * @return input stream of response
+   */
+  public InputStream asInputStream() {
+    return inputStream;
+  }
+
+  /**
+   * Retrieve response as String
+   * @return response as String
+   */
+  public String asString() {
+    String response;
+    try {
+      response = IOUtils.toString(inputStream);
+    } catch (IOException e) {
+      throw new ServiceFormattedException("Can't read from target host", e);
+    }
+    LOG.debug(String.format("Response: %s", response));
+
+    return response;
+  }
+
+  /**
+   * Retrieve response as JSON
+   * @return response as JSON
+   */
+  public JSONObject asJSON() {
+    String jsonString = asString();
+    return (JSONObject) JSONValue.parse(jsonString);
+  }
+
+  /**
+   * InputStream setter
+   * @param inputStream InputStream instance
+   */
+  public void setInputStream(InputStream inputStream) {
+    this.inputStream = inputStream;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/bb0116c3/contrib/views/capacity-scheduler/src/main/java/org/apache/ambari/view/capacityscheduler/utils/MisconfigurationFormattedException.java
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/java/org/apache/ambari/view/capacityscheduler/utils/MisconfigurationFormattedException.java b/contrib/views/capacity-scheduler/src/main/java/org/apache/ambari/view/capacityscheduler/utils/MisconfigurationFormattedException.java
new file mode 100644
index 0000000..2781be5
--- /dev/null
+++ b/contrib/views/capacity-scheduler/src/main/java/org/apache/ambari/view/capacityscheduler/utils/MisconfigurationFormattedException.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.view.capacityscheduler.utils;
+
+import org.json.simple.JSONObject;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.HashMap;
+
+/**
+ * Error on some Ambari View property was not set properly
+ */
+public class MisconfigurationFormattedException extends WebApplicationException {
+  private final static int STATUS = 500;
+  private final static String message = "Parameter \"%s\" is set to null";
+
+  public MisconfigurationFormattedException(String name) {
+    super(errorEntity(name));
+  }
+
+  protected static Response errorEntity(String name) {
+    HashMap<String, Object> response = new HashMap<String, Object>();
+    response.put("message", String.format(message, name));
+    response.put("trace", null);
+    response.put("status", STATUS);
+    return Response.status(STATUS).entity(new JSONObject(response)).type(MediaType.APPLICATION_JSON).build();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/bb0116c3/contrib/views/capacity-scheduler/src/main/java/org/apache/ambari/view/capacityscheduler/utils/ServiceFormattedException.java
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/java/org/apache/ambari/view/capacityscheduler/utils/ServiceFormattedException.java b/contrib/views/capacity-scheduler/src/main/java/org/apache/ambari/view/capacityscheduler/utils/ServiceFormattedException.java
new file mode 100644
index 0000000..45af095
--- /dev/null
+++ b/contrib/views/capacity-scheduler/src/main/java/org/apache/ambari/view/capacityscheduler/utils/ServiceFormattedException.java
@@ -0,0 +1,54 @@
+/**
+ * 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.view.capacityscheduler.utils;
+
+import org.apache.commons.lang.exception.ExceptionUtils;
+import org.json.simple.JSONObject;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.HashMap;
+
+/**
+ * General server error that provides verbose response
+ * to client with stack trace
+ */
+public class ServiceFormattedException extends WebApplicationException {
+  private final static int STATUS = 500;
+
+  public ServiceFormattedException(String message) {
+    this(message, null);
+  }
+
+  public ServiceFormattedException(String message, Throwable exception) {
+    super(errorEntity(message, exception));
+  }
+
+  protected static Response errorEntity(String message, Throwable e) {
+    HashMap<String, Object> response = new HashMap<String, Object>();
+    response.put("message", message);
+    String trace = null;
+    if (e != null)
+      trace = ExceptionUtils.getStackTrace(e);
+    response.put("trace", trace);
+    response.put("status", STATUS);
+    return Response.status(STATUS).entity(new JSONObject(response)).type(MediaType.APPLICATION_JSON).build();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/bb0116c3/contrib/views/capacity-scheduler/src/main/resources/ui/.gitignore
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/.gitignore b/contrib/views/capacity-scheduler/src/main/resources/ui/.gitignore
new file mode 100644
index 0000000..23e84db
--- /dev/null
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/.gitignore
@@ -0,0 +1,34 @@
+# Numerous always-ignore extensions
+*.diff
+*.err
+*.orig
+*.log
+*.rej
+*.swo
+*.swp
+*.vi
+*~
+*.sass-cache
+
+# OS or Editor folders
+.DS_Store
+.cache
+.project
+.settings
+.tmproj
+nbproject
+Thumbs.db
+
+# NPM packages folder.
+node_modules/
+
+bower_components/
+
+node/
+
+# Brunch folder for temporary files.
+tmp/
+
+public/
+
+_generators/

http://git-wip-us.apache.org/repos/asf/ambari/blob/bb0116c3/contrib/views/capacity-scheduler/src/main/resources/ui/app/adapters.js
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/adapters.js b/contrib/views/capacity-scheduler/src/main/resources/ui/app/adapters.js
new file mode 100644
index 0000000..50d31f6
--- /dev/null
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/adapters.js
@@ -0,0 +1,513 @@
+/**
+ * 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.
+ */
+
+var App = require('app');
+
+App.QueueAdapter = DS.Adapter.extend({
+  PREFIX: "yarn.scheduler.capacity",
+  queues: [],
+  clusterName: '',
+  tag: '',
+  createRecord: function(store, type, record) {
+    var data = this.serialize(record, { includeId: true });
+    return new Ember.RSVP.Promise(function(resolve, reject) {
+      return store.filter('queue',function (q) {
+        return q.id === record.id;
+      }).then(function (queues) {
+        var message;
+        if (record.get('name.length')==0) {
+          message = "Field can not be empty";
+        } else if (queues.get('length') > 1) {
+          message = "Queue already exists";
+        };
+        if (message) {
+          var error = new DS.InvalidError({path:[message]});
+          store.recordWasInvalid(record, error.errors);
+          return;
+        };
+
+        Ember.run(record, resolve, {'queue':data})
+
+      });
+    });
+  },
+
+  saveMark:'',
+
+  updateRecord:function (store,type,record) {
+    var adapter = this,
+        saveMark = this.get('saveMark'),
+        uri = _getCapacitySchedulerUri(adapter.clusterName, adapter.tag),
+        serializer = store.serializerFor('queue'),
+        props = serializer.serializeConfig(record);
+
+    if (saveMark) {
+      uri = [uri,saveMark].join('/');
+      this.set('saveMark','');
+    };
+
+    return new Ember.RSVP.Promise(function(resolve, reject) {
+      adapter.ajax(uri,'PUT',{data:props}).then(function(data) {
+        Ember.run(null, resolve, data);
+      }, function(jqXHR) {
+        jqXHR.then = null;
+        Ember.run(null, reject, jqXHR);
+      });
+    });
+  },
+  
+  /**
+   * Finds queue by id.
+   *
+   */
+  findQueue: function(id) {
+    var result = $.grep(App.Adapter.queues, function(e){ return e.get('id') == id; });
+    return result[0];
+  },
+
+  /**
+   * Finds queue by id in store.
+   *
+   */
+  find: function(store, type, id) {
+    return store.findAll('queue').then(function (queues) {
+      return {"queue":queues.findBy('id',id).toJSON({includeId:true})};
+    });
+  },
+
+  /**
+   * Finds all queues.
+   *
+   */
+  findAll: function(store, type) {
+    var adapter = this;
+    var uri = _getCapacitySchedulerUri(adapter.clusterName, adapter.tag);
+    return new Ember.RSVP.Promise(function(resolve, reject) {
+      adapter.ajax(uri).then(function(data) {
+        Ember.run(null, resolve, data);
+      }, function(jqXHR) {
+        jqXHR.then = null;
+        Ember.run(null, reject, jqXHR);
+      });
+    });
+
+  },
+     
+  /**
+   * Finds the cluster name.
+   *
+   */
+  findClusterName: function() {
+    var uri = _getClusterNameUri();
+        
+    return this.ajax(uri).then(function(data) {
+      var clusterName = data.ViewInstanceInfo.properties.clusterName;
+      console.log("found cluster name: "+clusterName);
+      App.Adapter.clusterName = clusterName;
+      return clusterName;
+    });
+  },
+
+  /**
+   * Finds the capacity scheduler tag.
+   */
+  findTag: function(clusterName) {
+    var uri = _getTagVersionUri(clusterName);
+    
+    return this.ajax(uri).then(function(data) {
+      var tag = data.Clusters.desired_configs["capacity-scheduler"].tag;
+      console.log("found tag version: "+tag);
+      App.Adapter.tag = tag;
+      return  tag;
+    })
+  },
+  
+  ajax: function(url, type, hash) {
+    var adapter = this;
+
+    return new Ember.RSVP.Promise(function(resolve, reject) {
+      hash = adapter.ajaxOptions(url, type, hash);
+
+      hash.success = function(json) {
+        Ember.run(null, resolve, json);
+      };
+
+      hash.error = function(jqXHR, textStatus, errorThrown) {
+        Ember.run(null, reject, adapter.ajaxError(jqXHR));
+      };
+
+      Ember.$.ajax(hash);
+    }, "DS: RestAdapter#ajax " + type + " to " + url);
+  },
+
+  ajaxOptions: function(url, type, hash) {
+    hash = hash || {};
+    hash.url = url;
+    hash.type = type;
+    hash.dataType = 'json';
+    hash.context = this;
+
+    if (hash.data && type !== 'GET') {
+      hash.contentType = 'application/json; charset=utf-8';
+      hash.data = JSON.stringify(hash.data);
+    }
+    hash.beforeSend = function (xhr) {
+      xhr.setRequestHeader('X-Requested-By', 'ambari');
+    };
+    return hash;
+  },
+
+  ajaxError: function(jqXHR) {
+    if (jqXHR && typeof jqXHR === 'object') {
+      jqXHR.then = null;
+    }
+
+    return jqXHR;
+  },
+});
+
+App.SchedulerAdapter = App.QueueAdapter.extend({
+  find: function(store, type, id) {
+    return store.findAll('scheduler').then(function (scheduler) {
+      return {"scheduler":scheduler.findBy('id',id).toJSON({includeId:true})};
+    });
+  },
+});
+
+App.ApplicationStore = DS.Store.extend({
+
+  adapter: App.QueueAdapter,
+
+  markForRefresh:function (mark) {
+    this.set('defaultAdapter.saveMark','saveAndRefresh');
+  },
+
+  markForRestart:function (mark) {
+    this.set('defaultAdapter.saveMark','saveAndRestart');
+  },
+
+  flushPendingSave: function() {
+    var pending = this._pendingSave.slice(),
+        newPending = [[]],scheduler;
+
+    if (pending.length == 1) {
+      this._super();
+      return;
+    };
+    
+    pending.forEach(function (tuple) {
+      var record = tuple[0], resolver = tuple[1],
+          operation;
+      newPending[0].push(record)
+      newPending[1] = resolver;
+    });
+
+    this._pendingSave = [newPending];
+    this._super();
+  },
+  didSaveRecord: function(record, data) {
+    if (Em.isArray(record)) {
+      for (var i = 0; i < record.length; i++) {
+        this._super(record[i],data.findBy('id',record[i].id));
+      };
+    } else {
+      this._super(record, data);
+    };
+  },
+  recordWasError: function(record) {
+    if (Em.isArray(record)) {
+      for (var i = 0; i < record.length; i++) {
+        record[i].adapterDidError();
+      };
+    } else {
+      record.adapterDidError();
+    }
+  },
+});
+
+App.ApplicationSerializer = DS.RESTSerializer.extend({
+
+  PREFIX:"yarn.scheduler.capacity",
+
+  serializeConfig:function (records) {
+    var config = {},
+        prefix = this.PREFIX;
+    records.forEach(function (record) {
+      if (record.id == 'scheduler') {
+        config[prefix + ".maximum-am-resource-percent"] = record.get('maximum_am_resource_percent');
+        config[prefix + ".maximum-applications"] = record.get('maximum_applications');
+        config[prefix + ".node-locality-delay"] = record.get('node_locality_delay');
+      } else {
+        config[prefix + "." + record.get('path') + ".unfunded.capacity"] = record.get('unfunded_capacity');
+        config[prefix + "." + record.get('path') + ".acl_administer_queue"] = record.get('acl_administer_queue');
+        config[prefix + "." + record.get('path') + ".acl_administer_jobs"] = record.get('acl_administer_jobs');
+        config[prefix + "." + record.get('path') + ".acl_submit_applications"] = record.get('acl_submit_applications');
+        config[prefix + "." + record.get('path') + ".minimum-user-limit-percent"] = record.get('minimum_user_limit_percent');
+        config[prefix + "." + record.get('path') + ".maximum-capacity"] = record.get('maximum_capacity');
+        config[prefix + "." + record.get('path') + ".user-limit-factor"] = record.get('user_limit_factor');
+        config[prefix + "." + record.get('path') + ".state"] = record.get('state');
+        config[prefix + "." + record.get('path') + ".capacity"] = record.get('capacity');
+        config[prefix + "." + record.get('path') + ".queues"] = record.get('queueNames')||'';
+      };
+    });
+
+    for (var i in config) {
+      if (config[i] === null || config[i] === undefined) {
+        delete config[i];
+      }
+    }
+
+    return {properties : config};
+
+  },
+  normalizeConfig:function (store, payload) {
+    var queues = [];
+    var props = payload.items[0].properties;
+
+    var scheduler = [{
+      id:'scheduler',
+      maximum_am_resource_percent:props[this.PREFIX + ".maximum-am-resource-percent"],
+      maximum_applications:props[this.PREFIX + ".maximum-applications"],
+      node_locality_delay:props[this.PREFIX + ".node-locality-delay"]
+    }];
+    queues = _recurseQueues(null, "root", 0, props, queues, store);
+
+    return {'queue':queues,'scheduler':scheduler};
+  },
+
+  extractFindAll: function(store, type, payload){
+    var queues = [];
+    var props = payload.items[0].properties;
+
+    var scheduler = {
+      id:'scheduler',
+      maximum_am_resource_percent:props[this.PREFIX + ".maximum-am-resource-percent"],
+      maximum_applications:props[this.PREFIX + ".maximum-applications"],
+      node_locality_delay:props[this.PREFIX + ".node-locality-delay"]
+    };
+    queues = _recurseQueues(null, "root", 0, props, queues, store);
+
+    var config = this.normalizeConfig(store, payload);
+    
+    return this.extractArray(store, type, config);
+  },
+
+  extractUpdateRecord:function (store, type, payload, id, requestType) {
+    var queues = [];
+    var props = payload.items[0].properties;
+
+    var scheduler = {
+      id:'scheduler',
+      maximum_am_resource_percent:props[this.PREFIX + ".maximum-am-resource-percent"],
+      maximum_applications:props[this.PREFIX + ".maximum-applications"],
+      node_locality_delay:props[this.PREFIX + ".node-locality-delay"]
+    };
+    queues = _recurseQueues(null, "root", 0, props, queues, store);
+    
+    var config = this.normalizeConfig(store, payload);
+
+    return this.extractConfig(store, App.Queue, {'queue':queues,'scheduler':[scheduler]});
+  },
+
+  extractConfig: function(store, primaryType, payload) {
+      payload = this.normalizePayload(payload);
+
+      var primaryTypeName = primaryType.typeKey,
+          primaryArray = [],
+          scheduler,queues;
+
+      for (var prop in payload) {
+        var typeKey = prop,
+            forcedSecondary = false;
+
+        if (prop.charAt(0) === '_') {
+          forcedSecondary = true;
+          typeKey = prop.substr(1);
+        }
+
+        var typeName = this.typeForRoot(typeKey),
+            type = store.modelFor(typeName),
+            typeSerializer = store.serializerFor(type),
+            isPrimary = (!forcedSecondary && (type.typeKey === primaryTypeName));
+
+        var normalizedArray = Ember.ArrayPolyfills.map.call(payload[prop], function(hash) {
+          return typeSerializer.normalize(type, hash, prop);
+        }, this);
+
+        if (typeKey == App.Scheduler.typeKey) {
+          scheduler = normalizedArray;
+        } else {
+          queues = normalizedArray;
+        }
+      }
+
+      return scheduler.concat(queues);
+    },
+
+  extractQueue: function(data, props) {
+    var q = { name: data.name, parentPath: data.parentPath, depth: data.depth };
+    var prefix = this.PREFIX;
+
+    if (q.parentPath == null || q.parentPath.length == 0){
+        q.path = q.name;
+      } else {
+        q.path = q.parentPath + '.' + q.name;
+      }
+      q.id = q.path.dasherize();
+
+    q.unfunded_capacity = props[prefix + "." + q.path + ".unfunded.capacity"];
+    q.acl_administer_queue = props[prefix + "." + q.path + ".acl_administer_queue"];
+    q.acl_administer_jobs = props[prefix + "." + q.path + ".acl_administer_jobs"];
+    q.acl_submit_applications = props[prefix + "." + q.path + ".acl_submit_applications"];
+    q.minimum_user_limit_percent = props[prefix + "." + q.path + ".minimum-user-limit-percent"];
+    q.maximum_capacity = props[prefix + "." + q.path + ".maximum-capacity"];
+    q.user_limit_factor = props[prefix + "." + q.path + ".user-limit-factor"];
+    q.state = props[prefix + "." + q.path + ".state"];
+
+    q.capacity = props[prefix + "." + q.path + ".capacity"];
+    q.queueNames = props[prefix + "." + q.path + ".queues"];
+
+    return q;
+  }
+});
+
+/**
+ * Recursively builds the list of queues.
+ *
+ */
+function _recurseQueues(parentQueue, queueName, depth, props, queues, store) {
+  var serializer = store.serializerFor('queue');
+  var prefix = serializer.PREFIX;
+  var parentPath = '';
+  if (parentQueue != null) {
+    parentPath = parentQueue.path;
+    prefix += ".";
+  }
+
+  var queue = serializer.extractQueue({ name: queueName, parentPath: parentPath, depth: depth}, props);
+  queues.push(queue);
+
+  var queueProp = prefix + parentPath + "." + queueName + ".queues";
+  if (props[queueProp]) {
+    var qs = props[queueProp].split(',');
+    for (var i=0; i < qs.length; i++) {
+      queues = _recurseQueues(queue, qs[i], depth+1, props, queues, store)
+    }
+  }
+  
+  return queues;
+}
+
+/**
+ * Gets the cluster name URI based on test mode
+ *
+ * @return  cluster name URI
+ */
+function _getCapacitySchedulerUri() {
+  if (App.testMode)
+    return  "/data/scheduler-configuration.json"
+
+  var parts = window.location.pathname.match(/\/[^\/]*/g);
+  var view = parts[1];
+  var version = '/versions' + parts[2];
+  var instance = parts[3];
+  if (parts.length == 4) { // version is not present
+    instance = parts[2];
+    version = '';
+  }
+  return '/api/v1/views' + view + version + '/instances' + instance+'/resources/scheduler/configuration';
+}
+
+/**
+ * Gets the cluster name URI based on test mode
+ *
+ * @return  cluster name URI
+ */
+function _getClusterNameUri() {
+  if (App.testMode)
+    return  "/data/view-instance.json"
+
+  var parts = window.location.pathname.match(/\/[^\/]*/g);
+  var view = parts[1];
+  var version = '/versions' + parts[2];
+  var instance = parts[3];
+  if (parts.length == 4) { // version is not present
+    instance = parts[2];
+    version = '';
+  }
+  return '/api/v1/views' + view + version + '/instances' + instance;
+}
+
+/**
+ * Gets the capacity scheduler URI based on test mode.
+ *
+ * @param   clusterName     the cluster name
+ * @param   tagVersion      the tag version
+ * @return  the capacity scheduler URI
+ */
+function _getCapacitySchedulerUri_old(clusterName, tagVersion) {
+  console.log("_getCapacitySchedulerUri.clusterName = "+clusterName);
+  console.log("_getCapacitySchedulerUri.tagVersion = "+tagVersion);
+  if (App.testMode)
+    return  "/data/capacity-scheduler.json"
+    
+  return "/api/v1/clusters/" + clusterName + "/configurations?type=capacity-scheduler&tag="+tagVersion;
+}
+
+/**
+ * Gets the tag version URI based on test mode.
+ *
+ * @param   clusterName     the cluster name
+ * @return  the capacity scheduler tag URI
+ */
+function _getTagVersionUri(clusterName) {
+  if (App.testMode)
+    return  "/data/cs-tag.json"
+    
+  return "/api/v1/clusters/" + clusterName + "?fields=Clusters/desired_configs/capacity-scheduler";
+}
+
+/**
+ * Setup claster name and version tag for adapter
+ */
+
+/*App.deferReadiness();
+
+(function () {
+
+  var clusterNameUri = _getClusterNameUri();
+    
+  return Em.$.ajax({url: clusterNameUri, dataType: "json"}).then(function(data) {
+    var clusterName = data.ViewInstanceInfo.properties.clusterName;
+    console.log("found cluster name: "+clusterName);
+
+    App.QueueAdapter.reopen({clusterName:clusterName});
+
+    var tagVersionUri = _getTagVersionUri(clusterName);
+  
+    return Em.$.ajax({url: tagVersionUri, dataType: "json"}).then(function(data) {
+      var tag = data.Clusters.desired_configs["capacity-scheduler"].tag;
+      console.log("found tag version: "+tag);
+
+      App.QueueAdapter.reopen({tag:tag});
+
+      App.advanceReadiness();
+
+    });
+  });
+})();*/

http://git-wip-us.apache.org/repos/asf/ambari/blob/bb0116c3/contrib/views/capacity-scheduler/src/main/resources/ui/app/app.js
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/app.js b/contrib/views/capacity-scheduler/src/main/resources/ui/app/app.js
new file mode 100644
index 0000000..33759f7
--- /dev/null
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/app.js
@@ -0,0 +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.
+ */
+
+module.exports = Em.Application.create();
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/bb0116c3/contrib/views/capacity-scheduler/src/main/resources/ui/app/assets/data/capacity-scheduler.json
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/assets/data/capacity-scheduler.json b/contrib/views/capacity-scheduler/src/main/resources/ui/app/assets/data/capacity-scheduler.json
new file mode 100644
index 0000000..bee7fa2
--- /dev/null
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/assets/data/capacity-scheduler.json
@@ -0,0 +1,90 @@
+{
+  "href" : "http://c6403.ambari.apache.org:8080/api/v1/clusters/MyCluster/configurations?type=capacity-scheduler&tag=version1400218672484",
+  "items" : [
+    {
+      "href" : "http://c6403.ambari.apache.org:8080/api/v1/clusters/MyCluster/configurations?type=capacity-scheduler&tag=version1400218672484",
+      "tag" : "version1400218672484",
+      "type" : "capacity-scheduler",
+      "Config" : {
+        "cluster_name" : "MyCluster"
+      },
+      "properties" : {
+        "yarn.scheduler.capacity.maximum-am-resource-percent" : "0.2",
+        "yarn.scheduler.capacity.maximum-applications" : "10000",
+        "yarn.scheduler.capacity.node-locality-delay" : "40",
+        "yarn.scheduler.capacity.root.Engineering.Development.acl_administer_jobs" : "*",
+        "yarn.scheduler.capacity.root.Engineering.Development.acl_administer_queue" : "*",
+        "yarn.scheduler.capacity.root.Engineering.Development.acl_submit_applications" : "*",
+        "yarn.scheduler.capacity.root.Engineering.Development.capacity" : "20",
+        "yarn.scheduler.capacity.root.Engineering.Development.maximum-capacity" : "100",
+        "yarn.scheduler.capacity.root.Engineering.Development.state" : "RUNNING",
+        "yarn.scheduler.capacity.root.Engineering.Development.user-limit-factor" : "1",
+        "yarn.scheduler.capacity.root.Engineering.QE.acl_administer_jobs" : "*",
+        "yarn.scheduler.capacity.root.Engineering.QE.acl_administer_queue" : " ",
+        "yarn.scheduler.capacity.root.Engineering.QE.acl_submit_applications" : "*",
+        "yarn.scheduler.capacity.root.Engineering.QE.capacity" : "80",
+        "yarn.scheduler.capacity.root.Engineering.QE.maximum-capacity" : "90",
+        "yarn.scheduler.capacity.root.Engineering.QE.state" : "RUNNING",
+        "yarn.scheduler.capacity.root.Engineering.QE.user-limit-factor" : "1",
+        "yarn.scheduler.capacity.root.Engineering.acl_administer_jobs" : "*",
+        "yarn.scheduler.capacity.root.Engineering.acl_administer_queue" : "user1,user2 group2",
+        "yarn.scheduler.capacity.root.Engineering.acl_submit_applications" : "*",
+        "yarn.scheduler.capacity.root.Engineering.capacity" : "60",
+        "yarn.scheduler.capacity.root.Engineering.maximum-capacity" : "100",
+        "yarn.scheduler.capacity.root.Engineering.queues" : "Development,QE",
+        "yarn.scheduler.capacity.root.Engineering.state" : "RUNNING",
+        "yarn.scheduler.capacity.root.Engineering.user-limit-factor" : "1",
+        "yarn.scheduler.capacity.root.Marketing.Advertising.acl_administer_jobs" : "*",
+        "yarn.scheduler.capacity.root.Marketing.Advertising.acl_administer_queue" : " ",
+        "yarn.scheduler.capacity.root.Marketing.Advertising.acl_submit_applications" : "*",
+        "yarn.scheduler.capacity.root.Marketing.Advertising.capacity" : "30",
+        "yarn.scheduler.capacity.root.Marketing.Advertising.maximum-capacity" : "40",
+        "yarn.scheduler.capacity.root.Marketing.Advertising.state" : "STOPPED",
+        "yarn.scheduler.capacity.root.Marketing.Advertising.user-limit-factor" : "1",
+        "yarn.scheduler.capacity.root.Marketing.Sales.acl_administer_jobs" : "*",
+        "yarn.scheduler.capacity.root.Marketing.Sales.acl_administer_queue" : " group5",
+        "yarn.scheduler.capacity.root.Marketing.Sales.acl_submit_applications" : "*",
+        "yarn.scheduler.capacity.root.Marketing.Sales.capacity" : "70",
+        "yarn.scheduler.capacity.root.Marketing.Sales.maximum-capacity" : "80",
+        "yarn.scheduler.capacity.root.Marketing.Sales.minimum-user-limit-percent" : "20",
+        "yarn.scheduler.capacity.root.Marketing.Sales.state" : "RUNNING",
+        "yarn.scheduler.capacity.root.Marketing.Sales.user-limit-factor" : "1",
+        "yarn.scheduler.capacity.root.Marketing.acl_administer_jobs" : "*",
+        "yarn.scheduler.capacity.root.Marketing.acl_submit_applications" : "*",
+        "yarn.scheduler.capacity.root.Marketing.acl_administer_queue" : " group5",
+        "yarn.scheduler.capacity.root.Marketing.capacity" : "10",
+        "yarn.scheduler.capacity.root.Marketing.maximum-capacity" : "40",
+        "yarn.scheduler.capacity.root.Marketing.queues" : "Sales,Advertising",
+        "yarn.scheduler.capacity.root.Marketing.state" : "RUNNING",
+        "yarn.scheduler.capacity.root.Marketing.user-limit-factor" : "1",
+        "yarn.scheduler.capacity.root.Support.Services.acl_administer_jobs" : "*",
+        "yarn.scheduler.capacity.root.Support.Services.acl_administer_queue" : "*",
+        "yarn.scheduler.capacity.root.Support.Services.acl_submit_applications" : "*",
+        "yarn.scheduler.capacity.root.Support.Services.capacity" : "80",
+        "yarn.scheduler.capacity.root.Support.Services.maximum-capacity" : "100",
+        "yarn.scheduler.capacity.root.Support.Services.minimum-user-limit-percent" : "20",
+        "yarn.scheduler.capacity.root.Support.Services.state" : "RUNNING",
+        "yarn.scheduler.capacity.root.Support.Services.user-limit-factor" : "1",
+        "yarn.scheduler.capacity.root.Support.Training.acl_administer_jobs" : "*",
+        "yarn.scheduler.capacity.root.Support.Training.acl_administer_queue" : "user2",
+        "yarn.scheduler.capacity.root.Support.Training.acl_submit_applications" : "*",
+        "yarn.scheduler.capacity.root.Support.Training.capacity" : "20",
+        "yarn.scheduler.capacity.root.Support.Training.maximum-capacity" : "60",
+        "yarn.scheduler.capacity.root.Support.Training.state" : "RUNNING",
+        "yarn.scheduler.capacity.root.Support.Training.user-limit-factor" : "1",
+        "yarn.scheduler.capacity.root.Support.acl_administer_jobs" : "*",
+        "yarn.scheduler.capacity.root.Support.acl_administer_queue" : " ",
+        "yarn.scheduler.capacity.root.Support.acl_submit_applications" : "*",
+        "yarn.scheduler.capacity.root.Support.capacity" : "30",
+        "yarn.scheduler.capacity.root.Support.maximum-capacity" : "100",
+        "yarn.scheduler.capacity.root.Support.queues" : "Training,Services",
+        "yarn.scheduler.capacity.root.Support.state" : "RUNNING",
+        "yarn.scheduler.capacity.root.Support.user-limit-factor" : "1",
+        "yarn.scheduler.capacity.root.acl_administer_queue" : "*",
+        "yarn.scheduler.capacity.root.capacity" : "100",
+        "yarn.scheduler.capacity.root.queues" : "Support,Marketing,Engineering",
+        "yarn.scheduler.capacity.root.unfunded.capacity" : "50"
+      }
+    }
+  ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/bb0116c3/contrib/views/capacity-scheduler/src/main/resources/ui/app/assets/data/cs-tag.json
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/assets/data/cs-tag.json b/contrib/views/capacity-scheduler/src/main/resources/ui/app/assets/data/cs-tag.json
new file mode 100644
index 0000000..dc63779
--- /dev/null
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/assets/data/cs-tag.json
@@ -0,0 +1,13 @@
+{
+  "href" : "http://c6401.ambari.apache.org:8080/api/v1/clusters/MyCluster?fields=Clusters/desired_configs/capacity-scheduler",
+  "Clusters" : {
+    "cluster_name" : "MyCluster",
+    "version" : "HDP-2.1",
+    "desired_configs" : {
+      "capacity-scheduler" : {
+        "user" : "admin",
+        "tag" : "version1"
+      }
+    }
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/bb0116c3/contrib/views/capacity-scheduler/src/main/resources/ui/app/assets/data/refreshqueues.json
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/assets/data/refreshqueues.json b/contrib/views/capacity-scheduler/src/main/resources/ui/app/assets/data/refreshqueues.json
new file mode 100644
index 0000000..46dd88b
--- /dev/null
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/assets/data/refreshqueues.json
@@ -0,0 +1,7 @@
+{
+  "href" : "http://c6403.ambari.apache.org:8080/api/v1/clusters/MyCluster/requests/29",
+  "Requests" : {
+    "id" : 29,
+    "status" : "InProgress"
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/bb0116c3/contrib/views/capacity-scheduler/src/main/resources/ui/app/assets/data/resourcemanager.json
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/assets/data/resourcemanager.json b/contrib/views/capacity-scheduler/src/main/resources/ui/app/assets/data/resourcemanager.json
new file mode 100644
index 0000000..efabc0b
--- /dev/null
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/assets/data/resourcemanager.json
@@ -0,0 +1,18 @@
+{
+  "href" : "http://c6401.ambari.apache.org:8080/api/v1/clusters/MyCluster/services/YARN/components/RESOURCEMANAGER?fields=host_components",
+  "ServiceComponentInfo" : {
+    "cluster_name" : "MyCluster",
+    "component_name" : "RESOURCEMANAGER",
+    "service_name" : "YARN"
+  },
+  "host_components" : [
+    {
+      "href" : "http://c6401.ambari.apache.org:8080/api/v1/clusters/MyCluster/hosts/c6401.ambari.apache.org/host_components/RESOURCEMANAGER",
+      "HostRoles" : {
+        "cluster_name" : "MyCluster",
+        "component_name" : "RESOURCEMANAGER",
+        "host_name" : "c6401.ambari.apache.org"
+      }
+    }
+  ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/bb0116c3/contrib/views/capacity-scheduler/src/main/resources/ui/app/assets/data/scheduler-configuration.json
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/assets/data/scheduler-configuration.json b/contrib/views/capacity-scheduler/src/main/resources/ui/app/assets/data/scheduler-configuration.json
new file mode 100644
index 0000000..bee7fa2
--- /dev/null
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/assets/data/scheduler-configuration.json
@@ -0,0 +1,90 @@
+{
+  "href" : "http://c6403.ambari.apache.org:8080/api/v1/clusters/MyCluster/configurations?type=capacity-scheduler&tag=version1400218672484",
+  "items" : [
+    {
+      "href" : "http://c6403.ambari.apache.org:8080/api/v1/clusters/MyCluster/configurations?type=capacity-scheduler&tag=version1400218672484",
+      "tag" : "version1400218672484",
+      "type" : "capacity-scheduler",
+      "Config" : {
+        "cluster_name" : "MyCluster"
+      },
+      "properties" : {
+        "yarn.scheduler.capacity.maximum-am-resource-percent" : "0.2",
+        "yarn.scheduler.capacity.maximum-applications" : "10000",
+        "yarn.scheduler.capacity.node-locality-delay" : "40",
+        "yarn.scheduler.capacity.root.Engineering.Development.acl_administer_jobs" : "*",
+        "yarn.scheduler.capacity.root.Engineering.Development.acl_administer_queue" : "*",
+        "yarn.scheduler.capacity.root.Engineering.Development.acl_submit_applications" : "*",
+        "yarn.scheduler.capacity.root.Engineering.Development.capacity" : "20",
+        "yarn.scheduler.capacity.root.Engineering.Development.maximum-capacity" : "100",
+        "yarn.scheduler.capacity.root.Engineering.Development.state" : "RUNNING",
+        "yarn.scheduler.capacity.root.Engineering.Development.user-limit-factor" : "1",
+        "yarn.scheduler.capacity.root.Engineering.QE.acl_administer_jobs" : "*",
+        "yarn.scheduler.capacity.root.Engineering.QE.acl_administer_queue" : " ",
+        "yarn.scheduler.capacity.root.Engineering.QE.acl_submit_applications" : "*",
+        "yarn.scheduler.capacity.root.Engineering.QE.capacity" : "80",
+        "yarn.scheduler.capacity.root.Engineering.QE.maximum-capacity" : "90",
+        "yarn.scheduler.capacity.root.Engineering.QE.state" : "RUNNING",
+        "yarn.scheduler.capacity.root.Engineering.QE.user-limit-factor" : "1",
+        "yarn.scheduler.capacity.root.Engineering.acl_administer_jobs" : "*",
+        "yarn.scheduler.capacity.root.Engineering.acl_administer_queue" : "user1,user2 group2",
+        "yarn.scheduler.capacity.root.Engineering.acl_submit_applications" : "*",
+        "yarn.scheduler.capacity.root.Engineering.capacity" : "60",
+        "yarn.scheduler.capacity.root.Engineering.maximum-capacity" : "100",
+        "yarn.scheduler.capacity.root.Engineering.queues" : "Development,QE",
+        "yarn.scheduler.capacity.root.Engineering.state" : "RUNNING",
+        "yarn.scheduler.capacity.root.Engineering.user-limit-factor" : "1",
+        "yarn.scheduler.capacity.root.Marketing.Advertising.acl_administer_jobs" : "*",
+        "yarn.scheduler.capacity.root.Marketing.Advertising.acl_administer_queue" : " ",
+        "yarn.scheduler.capacity.root.Marketing.Advertising.acl_submit_applications" : "*",
+        "yarn.scheduler.capacity.root.Marketing.Advertising.capacity" : "30",
+        "yarn.scheduler.capacity.root.Marketing.Advertising.maximum-capacity" : "40",
+        "yarn.scheduler.capacity.root.Marketing.Advertising.state" : "STOPPED",
+        "yarn.scheduler.capacity.root.Marketing.Advertising.user-limit-factor" : "1",
+        "yarn.scheduler.capacity.root.Marketing.Sales.acl_administer_jobs" : "*",
+        "yarn.scheduler.capacity.root.Marketing.Sales.acl_administer_queue" : " group5",
+        "yarn.scheduler.capacity.root.Marketing.Sales.acl_submit_applications" : "*",
+        "yarn.scheduler.capacity.root.Marketing.Sales.capacity" : "70",
+        "yarn.scheduler.capacity.root.Marketing.Sales.maximum-capacity" : "80",
+        "yarn.scheduler.capacity.root.Marketing.Sales.minimum-user-limit-percent" : "20",
+        "yarn.scheduler.capacity.root.Marketing.Sales.state" : "RUNNING",
+        "yarn.scheduler.capacity.root.Marketing.Sales.user-limit-factor" : "1",
+        "yarn.scheduler.capacity.root.Marketing.acl_administer_jobs" : "*",
+        "yarn.scheduler.capacity.root.Marketing.acl_submit_applications" : "*",
+        "yarn.scheduler.capacity.root.Marketing.acl_administer_queue" : " group5",
+        "yarn.scheduler.capacity.root.Marketing.capacity" : "10",
+        "yarn.scheduler.capacity.root.Marketing.maximum-capacity" : "40",
+        "yarn.scheduler.capacity.root.Marketing.queues" : "Sales,Advertising",
+        "yarn.scheduler.capacity.root.Marketing.state" : "RUNNING",
+        "yarn.scheduler.capacity.root.Marketing.user-limit-factor" : "1",
+        "yarn.scheduler.capacity.root.Support.Services.acl_administer_jobs" : "*",
+        "yarn.scheduler.capacity.root.Support.Services.acl_administer_queue" : "*",
+        "yarn.scheduler.capacity.root.Support.Services.acl_submit_applications" : "*",
+        "yarn.scheduler.capacity.root.Support.Services.capacity" : "80",
+        "yarn.scheduler.capacity.root.Support.Services.maximum-capacity" : "100",
+        "yarn.scheduler.capacity.root.Support.Services.minimum-user-limit-percent" : "20",
+        "yarn.scheduler.capacity.root.Support.Services.state" : "RUNNING",
+        "yarn.scheduler.capacity.root.Support.Services.user-limit-factor" : "1",
+        "yarn.scheduler.capacity.root.Support.Training.acl_administer_jobs" : "*",
+        "yarn.scheduler.capacity.root.Support.Training.acl_administer_queue" : "user2",
+        "yarn.scheduler.capacity.root.Support.Training.acl_submit_applications" : "*",
+        "yarn.scheduler.capacity.root.Support.Training.capacity" : "20",
+        "yarn.scheduler.capacity.root.Support.Training.maximum-capacity" : "60",
+        "yarn.scheduler.capacity.root.Support.Training.state" : "RUNNING",
+        "yarn.scheduler.capacity.root.Support.Training.user-limit-factor" : "1",
+        "yarn.scheduler.capacity.root.Support.acl_administer_jobs" : "*",
+        "yarn.scheduler.capacity.root.Support.acl_administer_queue" : " ",
+        "yarn.scheduler.capacity.root.Support.acl_submit_applications" : "*",
+        "yarn.scheduler.capacity.root.Support.capacity" : "30",
+        "yarn.scheduler.capacity.root.Support.maximum-capacity" : "100",
+        "yarn.scheduler.capacity.root.Support.queues" : "Training,Services",
+        "yarn.scheduler.capacity.root.Support.state" : "RUNNING",
+        "yarn.scheduler.capacity.root.Support.user-limit-factor" : "1",
+        "yarn.scheduler.capacity.root.acl_administer_queue" : "*",
+        "yarn.scheduler.capacity.root.capacity" : "100",
+        "yarn.scheduler.capacity.root.queues" : "Support,Marketing,Engineering",
+        "yarn.scheduler.capacity.root.unfunded.capacity" : "50"
+      }
+    }
+  ]
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/bb0116c3/contrib/views/capacity-scheduler/src/main/resources/ui/app/assets/data/view-instance.json
----------------------------------------------------------------------
diff --git a/contrib/views/capacity-scheduler/src/main/resources/ui/app/assets/data/view-instance.json b/contrib/views/capacity-scheduler/src/main/resources/ui/app/assets/data/view-instance.json
new file mode 100644
index 0000000..80bc06b
--- /dev/null
+++ b/contrib/views/capacity-scheduler/src/main/resources/ui/app/assets/data/view-instance.json
@@ -0,0 +1,15 @@
+{
+  "href" : "http://c6401.ambari.apache.org:8080/api/v1/views/CS/versions/0.1.0/instances/CS_1",
+  "ViewInstanceInfo" : {
+    "context_path" : "/views/CS/0.1.0/CS_1",
+    "instance_name" : "CS_1",
+    "version" : "0.1.0",
+    "view_name" : "CS",
+    "instance_data" : { },
+    "properties" : {
+      "clusterName" : "MyCluster"
+    }
+  },
+  "resources" : [
+  ]
+}
\ No newline at end of file