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