You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by su...@apache.org on 2014/07/02 19:36:51 UTC
[3/4] AMBARI-6176. Integrate python shell into Ambari-shell
module(subin)
http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/flash/AbstractFlash.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/flash/AbstractFlash.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/flash/AbstractFlash.java
new file mode 100644
index 0000000..58abb75
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/flash/AbstractFlash.java
@@ -0,0 +1,66 @@
+/**
+ * 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.shell.flash;
+
+import static java.lang.Thread.sleep;
+
+import java.util.logging.Level;
+
+import org.springframework.shell.core.JLineShellComponent;
+
+/**
+ * Base class for showing flash messages.
+ */
+public abstract class AbstractFlash implements Runnable {
+
+ private static final int SLEEP_TIME = 1500;
+ private volatile boolean stop;
+ private FlashType flashType;
+ private JLineShellComponent shell;
+
+ protected AbstractFlash(JLineShellComponent shell, FlashType flashType) {
+ this.shell = shell;
+ this.flashType = flashType;
+ }
+
+ @Override
+ public void run() {
+ while (!stop) {
+ String text = null;
+ try {
+ text = getText();
+ if (text.isEmpty()) {
+ stop = true;
+ }
+ sleep(SLEEP_TIME);
+ } catch (Exception e) {
+ // ignore
+ } finally {
+ shell.flash(Level.SEVERE, text == null ? "" : text, flashType.getName());
+ }
+ }
+ }
+
+ /**
+ * Returns the actual text of the flash messages. To remove the flash
+ * return an empty string.
+ *
+ * @return message
+ */
+ public abstract String getText();
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/flash/FlashService.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/flash/FlashService.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/flash/FlashService.java
new file mode 100644
index 0000000..78977a6
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/flash/FlashService.java
@@ -0,0 +1,47 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.shell.flash;
+
+import java.util.concurrent.ExecutorService;
+
+import org.apache.ambari.groovy.client.AmbariClient;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.shell.core.JLineShellComponent;
+import org.springframework.stereotype.Service;
+
+/**
+ * Service for managing the flashes.
+ */
+@Service
+public class FlashService {
+
+ private AmbariClient client;
+ private JLineShellComponent shell;
+ private ExecutorService executorService;
+
+ @Autowired
+ public FlashService(AmbariClient client, JLineShellComponent shell, ExecutorService executorService) {
+ this.client = client;
+ this.shell = shell;
+ this.executorService = executorService;
+ }
+
+ public void showInstallProgress(boolean exit) {
+ executorService.submit(new InstallProgress(shell, client, exit));
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/flash/FlashType.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/flash/FlashType.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/flash/FlashType.java
new file mode 100644
index 0000000..754a269
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/flash/FlashType.java
@@ -0,0 +1,39 @@
+/**
+ * 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.shell.flash;
+
+/**
+ * Holds the unique names of the flashes.
+ */
+public enum FlashType {
+
+ /**
+ * Install progress percentage flash.
+ */
+ INSTALL("install");
+
+ private String name;
+
+ private FlashType(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/flash/InstallProgress.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/flash/InstallProgress.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/flash/InstallProgress.java
new file mode 100644
index 0000000..69164ea
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/flash/InstallProgress.java
@@ -0,0 +1,79 @@
+/**
+ * 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.shell.flash;
+
+import static java.lang.Math.round;
+
+import java.math.BigDecimal;
+
+import org.apache.ambari.groovy.client.AmbariClient;
+import org.springframework.shell.core.JLineShellComponent;
+
+/**
+ * Show the install progress in % value.
+ */
+public class InstallProgress extends AbstractFlash {
+
+ private static final int SUCCESS = 100;
+ private static final int FAILED = -1;
+ private final boolean exit;
+ private AmbariClient client;
+ private volatile boolean done;
+
+ public InstallProgress(JLineShellComponent shell, AmbariClient client, boolean exit) {
+ super(shell, FlashType.INSTALL);
+ this.client = client;
+ this.exit = exit;
+ }
+
+ @Override
+ public String getText() {
+ StringBuilder sb = new StringBuilder();
+ if (!done) {
+ BigDecimal progress = client.getInstallProgress();
+ if (progress != null) {
+ BigDecimal decimal = progress.setScale(2, BigDecimal.ROUND_HALF_UP);
+ int intValue = decimal.intValue();
+ if (intValue != SUCCESS && intValue != FAILED) {
+ sb.append("Installation: ").append(decimal).append("% ");
+ int rounded = round(progress.setScale(0, BigDecimal.ROUND_UP).intValue() / 10);
+ for (int i = 0; i < 10; i++) {
+ if (i < rounded) {
+ sb.append("=");
+ } else {
+ sb.append("-");
+ }
+ }
+ } else if (intValue == FAILED) {
+ sb.append("Installation: FAILED");
+ done = true;
+ } else {
+ sb.append("Installation: COMPLETE");
+ done = true;
+ }
+ } else {
+ sb.append("Installation: WAITING..");
+ }
+ } else {
+ if (exit) {
+ System.exit(0);
+ }
+ }
+ return sb.toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/model/AmbariContext.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/model/AmbariContext.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/model/AmbariContext.java
new file mode 100644
index 0000000..af45dd6
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/model/AmbariContext.java
@@ -0,0 +1,159 @@
+/**
+ * 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.shell.model;
+
+import org.springframework.stereotype.Component;
+
+/**
+ * Holds information about the connected Ambari Server.
+ */
+@Component
+public class AmbariContext {
+
+ private String cluster;
+ private boolean blueprintsAvailable;
+ private Focus focus;
+ private Hints hint;
+
+ public AmbariContext() {
+ this.focus = getRootFocus();
+ }
+
+ /**
+ * Sets the name of the cluster.
+ *
+ * @param cluster
+ */
+ public void setCluster(String cluster) {
+ this.cluster = cluster;
+ }
+
+ /**
+ * Sets the focus to the root.
+ */
+ public void resetFocus() {
+ this.focus = getRootFocus();
+ }
+
+ /**
+ * Sets the focus.
+ *
+ * @param id target of the focus, can be anything (blueprint id, host id..)
+ * @param type type of the focus
+ */
+ public void setFocus(String id, FocusType type) {
+ this.focus = new Focus(id, type);
+ }
+
+ /**
+ * Returns the target of the focus.
+ *
+ * @return target
+ */
+ public String getFocusValue() {
+ return focus.getValue();
+ }
+
+ /**
+ * Checks whether blueprints are available or not.
+ */
+ public boolean areBlueprintsAvailable() {
+ return blueprintsAvailable;
+ }
+
+ /**
+ * Sets what should be the next hint message.
+ *
+ * @param hint the new message
+ */
+ public void setHint(Hints hint) {
+ this.hint = hint;
+ }
+
+ /**
+ * Returns the context sensitive prompt.
+ *
+ * @return text of the prompt
+ */
+ public String getPrompt() {
+ return focus.isType(FocusType.ROOT) ?
+ isConnectedToCluster() ? formatPrompt(focus.getPrefix(), cluster) : "ambari-shell>" :
+ formatPrompt(focus.getPrefix(), focus.getValue());
+ }
+
+ public boolean isConnectedToCluster() {
+ return cluster != null;
+ }
+
+ /**
+ * Checks whether the focus is on the host or not.
+ *
+ * @return true if the focus is on a host false otherwise
+ */
+ public boolean isFocusOnHost() {
+ return isFocusOn(FocusType.HOST);
+ }
+
+ /**
+ * Checks whether the focus is on the cluster build or not.
+ *
+ * @return true if the focus is on a cluster build false otherwise
+ */
+ public boolean isFocusOnClusterBuild() {
+ return isFocusOn(FocusType.CLUSTER_BUILD);
+ }
+
+ /**
+ * Returns some context sensitive hint.
+ *
+ * @return hint
+ */
+ public String getHint() {
+ return "Hint: " + hint.message();
+ }
+
+ /**
+ * Returns the name of the cluster.
+ *
+ * @return cluster's name
+ */
+ public String getCluster() {
+ return cluster;
+ }
+
+ /**
+ * Sets whether there are blueprints available or not.
+ *
+ * @param blueprintsAvailable
+ */
+ public void setBlueprintsAvailable(boolean blueprintsAvailable) {
+ this.blueprintsAvailable = blueprintsAvailable;
+ }
+
+ private boolean isFocusOn(FocusType type) {
+ return focus.isType(type);
+ }
+
+ private Focus getRootFocus() {
+ return new Focus("root", FocusType.ROOT);
+ }
+
+ private String formatPrompt(String prefix, String postfix) {
+ return String.format("%s:%s>", prefix, postfix);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/model/Focus.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/model/Focus.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/model/Focus.java
new file mode 100644
index 0000000..b637c87
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/model/Focus.java
@@ -0,0 +1,53 @@
+/**
+ * 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.shell.model;
+
+/**
+ * Holds information about the focus. Focus give you the ability to
+ * provide context sensitive commands.
+ *
+ * @see org.apache.ambari.shell.model.FocusType
+ */
+public class Focus {
+
+ private final String value;
+ private final FocusType type;
+
+ public Focus(String value, FocusType type) {
+ this.value = value;
+ this.type = type;
+ }
+
+ public String getPrefix() {
+ return type.prefix();
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ /**
+ * Checks if the current focus exists with the provided one.
+ *
+ * @param type type to check with the current
+ * @return true if they match false otherwise
+ */
+ public boolean isType(FocusType type) {
+ return this.type == type;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/model/FocusType.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/model/FocusType.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/model/FocusType.java
new file mode 100644
index 0000000..121f7b4
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/model/FocusType.java
@@ -0,0 +1,55 @@
+/**
+ * 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.shell.model;
+
+/**
+ * Types for different focuses. Its purpose to give the command availability
+ * checkers a chance in decision making.
+ */
+public enum FocusType {
+
+ /**
+ * The focus is on a selected host.
+ */
+ HOST("HOST"),
+
+ /**
+ * The focus is on the cluster building phase.
+ */
+ CLUSTER_BUILD("CLUSTER_BUILD"),
+
+ /**
+ * No focus at all.
+ */
+ ROOT("CLUSTER");
+
+ private final String prefix;
+
+ private FocusType(String prefix) {
+ this.prefix = prefix;
+ }
+
+ /**
+ * Prefix provided for the prompt.
+ *
+ * @return focus prefix
+ */
+ public String prefix() {
+ return prefix;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/model/Hints.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/model/Hints.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/model/Hints.java
new file mode 100644
index 0000000..990c832
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/model/Hints.java
@@ -0,0 +1,59 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.shell.model;
+
+/**
+ * Provides some guidance's to the user, what he/she can follow.
+ */
+public enum Hints {
+
+ /**
+ * Hint for adding blueprints.
+ */
+ ADD_BLUEPRINT("Add a blueprint with the 'blueprint add' or add the default blueprints with the 'blueprint defaults' command."),
+
+ /**
+ * Hint for start building a cluster.
+ */
+ BUILD_CLUSTER("Start building a cluster with the 'cluster build' command using a previously added blueprint."),
+
+ /**
+ * Hint for start assigning hosts to host groups in cluster build phase.
+ */
+ ASSIGN_HOSTS("Assign hosts to different host groups with the 'cluster assign' command."),
+
+ /**
+ * Hint for create a cluster from the assigned hosts.
+ */
+ CREATE_CLUSTER("Create the cluster with the 'cluster create' command or use the 'cluster reset' command and start over."),
+
+ /**
+ * Hint for check the cluster creation result.
+ */
+ PROGRESS("See the install progress with the 'tasks' command.");
+
+ private final String message;
+
+ private Hints(String message) {
+ this.message = message;
+ }
+
+ public String message() {
+ return message;
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/support/TableRenderer.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/support/TableRenderer.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/support/TableRenderer.java
new file mode 100644
index 0000000..3e5af1f
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/support/TableRenderer.java
@@ -0,0 +1,121 @@
+/**
+ * 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.shell.support;
+
+import static java.util.Collections.singletonList;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.shell.support.table.Table;
+import org.springframework.shell.support.table.TableHeader;
+
+/**
+ * Utility class used to render tables.
+ */
+public final class TableRenderer {
+
+ private TableRenderer() {
+ throw new IllegalStateException();
+ }
+
+ /**
+ * Renders a 2 columns wide table with the given headers and rows. If headers are provided it should match with the
+ * number of columns.
+ *
+ * @param rows rows of the table
+ * @param headers headers of the table
+ * @return the formatted table
+ */
+ public static String renderSingleMap(Map<String, String> rows, String... headers) {
+ return renderMultiValueMap(convert(rows), headers);
+ }
+
+ /**
+ * Renders a 2 columns wide table with the given headers and rows. If headers are provided it should match with the
+ * number of columns.
+ *
+ * @param rows rows of the table, each value will be added as a new row with the same key
+ * @param headers headers of the table
+ * @return formatted table
+ */
+ public static String renderMultiValueMap(Map<String, List<String>> rows, String... headers) {
+ Table table = createTable(headers);
+ if (rows != null) {
+ for (String key : rows.keySet()) {
+ List<String> values = rows.get(key);
+ if (values != null) {
+ for (String value : values) {
+ table.addRow(key, value);
+ }
+ }
+ }
+ }
+ return format(table);
+ }
+
+ /**
+ * Renders a 3 columns wide table with the given headers and rows. If headers are provided it should match with the
+ * number of columns.
+ *
+ * @param rows rows of the table, value map will be added as the last 2 columns to the table
+ * @param headers headers of the table
+ * @return formatted table
+ */
+ public static String renderMapValueMap(Map<String, Map<String, String>> rows, String... headers) {
+ Table table = createTable(headers);
+ if (rows != null) {
+ for (String key1 : rows.keySet()) {
+ Map<String, String> values = rows.get(key1);
+ if (values != null) {
+ for (String key2 : values.keySet()) {
+ table.addRow(key1, key2, values.get(key2));
+ }
+ }
+ }
+ }
+ return format(table);
+ }
+
+ private static Table createTable(String... headers) {
+ Table table = new Table();
+ if (headers != null) {
+ int column = 1;
+ for (String header : headers) {
+ table.addHeader(column++, new TableHeader(header));
+ }
+ }
+ return table;
+ }
+
+ private static Map<String, List<String>> convert(Map<String, String> map) {
+ Map<String, List<String>> result = new HashMap<String, List<String>>(map.size());
+ if (map != null) {
+ for (String key : map.keySet()) {
+ result.put(key, singletonList(map.get(key)));
+ }
+ }
+ return result;
+ }
+
+ private static String format(Table table) {
+ table.calculateColumnWidths();
+ return table.toString();
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/main/resources/elephant.txt
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/resources/elephant.txt b/ambari-shell/ambari-groovy-shell/src/main/resources/elephant.txt
new file mode 100644
index 0000000..f51e284
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/resources/elephant.txt
@@ -0,0 +1,8 @@
+ .-.._
+ __ /` '.
+ .-' `/ ( a \
+ / ( \,_ \
+ /| '---` |\ =|
+ ` \ /__.-/ / | |
+ | / / \ \ \ \_\
+ |__|_| |_|__\
http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/test/java/org/apache/ambari/shell/commands/BlueprintCommandsTest.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/test/java/org/apache/ambari/shell/commands/BlueprintCommandsTest.java b/ambari-shell/ambari-groovy-shell/src/test/java/org/apache/ambari/shell/commands/BlueprintCommandsTest.java
new file mode 100644
index 0000000..3c9277c
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/test/java/org/apache/ambari/shell/commands/BlueprintCommandsTest.java
@@ -0,0 +1,128 @@
+/**
+ * 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.shell.commands;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+
+import org.apache.ambari.groovy.client.AmbariClient;
+import org.apache.ambari.shell.model.AmbariContext;
+import org.apache.ambari.shell.model.Hints;
+import org.apache.commons.io.IOUtils;
+import org.codehaus.jackson.JsonNode;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import groovyx.net.http.HttpResponseException;
+
+@RunWith(MockitoJUnitRunner.class)
+public class BlueprintCommandsTest {
+
+ @InjectMocks
+ private BlueprintCommands blueprintCommands;
+
+ @Mock
+ private AmbariClient ambariClient;
+ @Mock
+ private HttpResponseException responseException;
+ @Mock
+ private AmbariContext context;
+ @Mock
+ private ObjectMapper objectMapper;
+
+ @Test
+ public void testAddBlueprintForFileReadPrecedence() throws IOException {
+ File file = new File("src/test/resources/testBlueprint.json");
+ String json = IOUtils.toString(new FileInputStream(file));
+ JsonNode jsonNode = mock(JsonNode.class);
+ when(objectMapper.readTree(json.getBytes())).thenReturn(jsonNode);
+ when(jsonNode.get("Blueprints")).thenReturn(jsonNode);
+ when(jsonNode.get("blueprint_name")).thenReturn(jsonNode);
+ when(jsonNode.asText()).thenReturn("blueprintName");
+
+ String result = blueprintCommands.addBlueprint("url", file);
+
+ verify(ambariClient).addBlueprint(json);
+ verify(context).setHint(Hints.BUILD_CLUSTER);
+ verify(context).setBlueprintsAvailable(true);
+ assertEquals("Blueprint: 'blueprintName' has been added", result);
+ }
+
+ @Test
+ public void testAddBlueprintForException() throws IOException {
+ File file = new File("src/test/resources/testBlueprint.json");
+ String json = IOUtils.toString(new FileInputStream(file));
+ doThrow(responseException).when(ambariClient).addBlueprint(json);
+ when(responseException.getMessage()).thenReturn("error");
+
+ String result = blueprintCommands.addBlueprint("url", file);
+
+ verify(ambariClient).addBlueprint(json);
+ verify(responseException).getMessage();
+ assertEquals("Cannot add blueprint: error", result);
+ }
+
+ @Test
+ public void testAddBlueprintForDefaults() throws HttpResponseException {
+ String result = blueprintCommands.addBlueprint();
+
+ verify(ambariClient).addDefaultBlueprints();
+ assertEquals("Default blueprints added", result);
+ }
+
+ @Test
+ public void testAddBlueprintForUnspecifiedValue() throws HttpResponseException {
+ String response = blueprintCommands.addBlueprint(null, null);
+
+ assertEquals("No blueprint specified", response);
+ verify(ambariClient, times(0)).addBlueprint(null);
+ }
+
+ @Test
+ public void testAddBlueprintDefaultsForException() throws HttpResponseException {
+ doThrow(responseException).when(ambariClient).addDefaultBlueprints();
+ when(responseException.getMessage()).thenReturn("error");
+
+ String result = blueprintCommands.addBlueprint();
+
+ verify(responseException).getMessage();
+ assertEquals("Failed to add the default blueprints: error", result);
+ }
+
+ @Test
+ public void testAddBlueprintDefaultsForConnectionRefused() throws HttpResponseException {
+ doThrow(new RuntimeException("Connection refused")).when(ambariClient).addDefaultBlueprints();
+ when(responseException.getMessage()).thenReturn("error");
+
+ String result = blueprintCommands.addBlueprint();
+
+ assertEquals("Failed to add the default blueprints: Connection refused", result);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/test/java/org/apache/ambari/shell/commands/ClusterCommandsTest.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/test/java/org/apache/ambari/shell/commands/ClusterCommandsTest.java b/ambari-shell/ambari-groovy-shell/src/test/java/org/apache/ambari/shell/commands/ClusterCommandsTest.java
new file mode 100644
index 0000000..777d05d
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/test/java/org/apache/ambari/shell/commands/ClusterCommandsTest.java
@@ -0,0 +1,279 @@
+/**
+ * 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.shell.commands;
+
+import static java.util.Arrays.asList;
+import static java.util.Collections.emptyList;
+import static java.util.Collections.singletonMap;
+import static org.apache.ambari.shell.support.TableRenderer.renderMultiValueMap;
+import static org.apache.ambari.shell.support.TableRenderer.renderSingleMap;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.ambari.groovy.client.AmbariClient;
+import org.apache.ambari.shell.completion.Blueprint;
+import org.apache.ambari.shell.completion.Host;
+import org.apache.ambari.shell.flash.FlashService;
+import org.apache.ambari.shell.model.AmbariContext;
+import org.apache.ambari.shell.model.Hints;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import groovyx.net.http.HttpResponseException;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ClusterCommandsTest {
+
+ @InjectMocks
+ private ClusterCommands clusterCommands;
+
+ @Mock
+ private AmbariClient client;
+ @Mock
+ private AmbariContext context;
+ @Mock
+ private HttpResponseException responseException;
+ @Mock
+ private FlashService flashService;
+
+ @Test
+ public void testIsClusterBuildCommandAvailable() {
+ when(context.isConnectedToCluster()).thenReturn(false);
+ when(context.isFocusOnClusterBuild()).thenReturn(false);
+ when(context.areBlueprintsAvailable()).thenReturn(true);
+
+ boolean result = clusterCommands.isClusterBuildCommandAvailable();
+
+ assertTrue(result);
+ }
+
+ @Test
+ public void testIsClusterBuildCommandAvailableAndFocusOnBuild() {
+ when(context.isConnectedToCluster()).thenReturn(false);
+ when(context.isFocusOnClusterBuild()).thenReturn(true);
+ when(context.areBlueprintsAvailable()).thenReturn(true);
+
+ boolean result = clusterCommands.isClusterBuildCommandAvailable();
+
+ assertFalse(result);
+ }
+
+ @Test
+ public void testIsClusterBuildCommandAvailableAndNoBlueprints() {
+ when(context.isConnectedToCluster()).thenReturn(false);
+ when(context.isFocusOnClusterBuild()).thenReturn(false);
+ when(context.areBlueprintsAvailable()).thenReturn(false);
+
+ boolean result = clusterCommands.isClusterBuildCommandAvailable();
+
+ assertFalse(result);
+ }
+
+ @Test
+ public void testBuildClusterForNonExistingBlueprint() {
+ when(client.doesBlueprintExist("id")).thenReturn(false);
+
+ String result = clusterCommands.buildCluster(new Blueprint("id"));
+
+ verify(client).doesBlueprintExist("id");
+ assertEquals("Not a valid blueprint id", result);
+ }
+
+ @Test
+ public void testBuildCluster() {
+ Map<String, String> hostNames = singletonMap("host1", "HEALTHY");
+ Map<String, List<String>> map = singletonMap("group1", asList("comp1", "comp2"));
+ when(client.doesBlueprintExist("id")).thenReturn(true);
+ when(client.getBlueprintMap("id")).thenReturn(map);
+ when(context.getFocusValue()).thenReturn("id");
+ when(client.getHostNames()).thenReturn(hostNames);
+
+ String result = clusterCommands.buildCluster(new Blueprint("id"));
+
+ verify(client).doesBlueprintExist("id");
+ verify(client).getBlueprintMap("id");
+ verify(client).getHostGroups("id");
+ assertEquals(String.format("%s\n%s", renderSingleMap(hostNames, "HOSTNAME", "STATE"),
+ renderMultiValueMap(map, "HOSTGROUP", "COMPONENT")), result);
+ }
+
+ @Test
+ public void testAssignForInvalidHostGroup() {
+ Map<String, List<String>> map = singletonMap("group1", asList("host", "host2"));
+ ReflectionTestUtils.setField(clusterCommands, "hostGroups", map);
+ when(client.getHostNames()).thenReturn(singletonMap("host3", "HEALTHY"));
+
+ String result = clusterCommands.assign(new Host("host3"), "group0");
+
+ assertEquals("group0 is not a valid host group", result);
+ }
+
+ @Test
+ public void testAssignForValidHostGroup() {
+ Map<String, List<String>> map = new HashMap<String, List<String>>();
+ map.put("group1", new ArrayList<String>());
+ ReflectionTestUtils.setField(clusterCommands, "hostGroups", map);
+ when(client.getHostNames()).thenReturn(singletonMap("host3", "HEALTHY"));
+
+ String result = clusterCommands.assign(new Host("host3"), "group1");
+
+ assertEquals("host3 has been added to group1", result);
+ }
+
+ @Test
+ public void testAssignForInvalidHost() {
+ Map<String, List<String>> map = new HashMap<String, List<String>>();
+ map.put("group1", new ArrayList<String>());
+ ReflectionTestUtils.setField(clusterCommands, "hostGroups", map);
+ when(client.getHostNames()).thenReturn(singletonMap("host2", "HEALTHY"));
+
+ String result = clusterCommands.assign(new Host("host3"), "group1");
+
+ assertEquals("host3 is not a valid hostname", result);
+ }
+
+ @Test
+ public void testCreateClusterForException() throws HttpResponseException {
+ String blueprint = "blueprint";
+ Map<String, List<String>> map = singletonMap("group1", asList("host", "host2"));
+ ReflectionTestUtils.setField(clusterCommands, "hostGroups", map);
+ when(context.getFocusValue()).thenReturn(blueprint);
+ doThrow(responseException).when(client).createCluster(blueprint, blueprint, map);
+ doThrow(responseException).when(client).deleteCluster(blueprint);
+
+ String result = clusterCommands.createCluster(false);
+
+ verify(client).createCluster(blueprint, blueprint, map);
+ verify(client).getHostGroups(blueprint);
+ verify(client).deleteCluster(blueprint);
+ assertTrue(result.contains("Failed"));
+ }
+
+ @Test
+ public void testCreateCluster() throws HttpResponseException {
+ String blueprint = "blueprint";
+ Map<String, List<String>> map = singletonMap("group1", asList("host", "host2"));
+ ReflectionTestUtils.setField(clusterCommands, "hostGroups", map);
+ when(context.getFocusValue()).thenReturn(blueprint);
+ when(client.getClusterName()).thenReturn("cluster");
+
+ String result = clusterCommands.createCluster(false);
+
+ verify(client).createCluster(blueprint, blueprint, map);
+ verify(context).resetFocus();
+ assertFalse(result.contains("Failed"));
+ assertTrue(result.contains("Successfully"));
+ }
+
+ @Test
+ public void testDeleteClusterForException() throws HttpResponseException {
+ when(context.getCluster()).thenReturn("cluster");
+ when(responseException.getMessage()).thenReturn("msg");
+ doThrow(responseException).when(client).deleteCluster("cluster");
+
+ String result = clusterCommands.deleteCluster();
+
+ verify(client).deleteCluster("cluster");
+ verify(context).getCluster();
+ verify(responseException).getMessage();
+ assertEquals("Could not delete the cluster: msg", result);
+ }
+
+ @Test
+ public void testDeleteCluster() throws HttpResponseException {
+ when(context.getCluster()).thenReturn("cluster");
+ when(responseException.getMessage()).thenReturn("msg");
+
+ String result = clusterCommands.deleteCluster();
+
+ verify(client).deleteCluster("cluster");
+ verify(context).getCluster();
+ assertEquals("Successfully deleted the cluster", result);
+ }
+
+ @Test
+ public void testIsClusterPreviewCommandAvailable() {
+ when(context.isFocusOnClusterBuild()).thenReturn(true);
+ ReflectionTestUtils.setField(clusterCommands, "hostGroups", singletonMap("group1", asList("host1")));
+
+ boolean result = clusterCommands.isClusterPreviewCommandAvailable();
+
+ assertTrue(result);
+ }
+
+ @Test
+ public void testIsClusterPreviewCommandAvailableForNoAssignments() {
+ when(context.isFocusOnClusterBuild()).thenReturn(true);
+ ReflectionTestUtils.setField(clusterCommands, "hostGroups", singletonMap("group1", emptyList()));
+
+ boolean result = clusterCommands.isClusterPreviewCommandAvailable();
+
+ assertFalse(result);
+ }
+
+ @Test
+ public void testIsClusterResetCommandAvailable() {
+ when(context.isFocusOnClusterBuild()).thenReturn(true);
+ ReflectionTestUtils.setField(clusterCommands, "hostGroups", singletonMap("group1", asList("host1")));
+
+ boolean result = clusterCommands.isClusterResetCommandAvailable();
+
+ assertTrue(result);
+ }
+
+ @Test
+ public void testAutoAssignForEmptyResult() {
+ Map<String, List<String>> hostGroups = singletonMap("group1", asList("host1"));
+ ReflectionTestUtils.setField(clusterCommands, "hostGroups", hostGroups);
+ when(context.getFocusValue()).thenReturn("blueprint");
+ when(client.recommendAssignments("blueprint")).thenReturn(new HashMap<String, List<String>>());
+
+ clusterCommands.autoAssign();
+
+ Map<String, List<String>> result = (Map<String, List<String>>) ReflectionTestUtils.getField(clusterCommands, "hostGroups");
+ assertEquals(hostGroups, result);
+ }
+
+ @Test
+ public void testAutoAssign() {
+ Map<String, List<String>> hostGroups = singletonMap("group1", asList("host1"));
+ Map<String, List<String>> newAssignments = singletonMap("group1", asList("host1"));
+ ReflectionTestUtils.setField(clusterCommands, "hostGroups", hostGroups);
+ when(context.getFocusValue()).thenReturn("blueprint");
+ when(client.recommendAssignments("blueprint")).thenReturn(newAssignments);
+
+ clusterCommands.autoAssign();
+
+ Map<String, List<String>> result = (Map<String, List<String>>) ReflectionTestUtils.getField(clusterCommands, "hostGroups");
+ assertEquals(newAssignments, result);
+ verify(context).setHint(Hints.CREATE_CLUSTER);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/test/java/org/apache/ambari/shell/commands/HostCommandsTest.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/test/java/org/apache/ambari/shell/commands/HostCommandsTest.java b/ambari-shell/ambari-groovy-shell/src/test/java/org/apache/ambari/shell/commands/HostCommandsTest.java
new file mode 100644
index 0000000..6ca6d4d
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/test/java/org/apache/ambari/shell/commands/HostCommandsTest.java
@@ -0,0 +1,66 @@
+/**
+ * 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.shell.commands;
+
+import static java.util.Collections.singletonMap;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import org.apache.ambari.groovy.client.AmbariClient;
+import org.apache.ambari.shell.completion.Host;
+import org.apache.ambari.shell.model.AmbariContext;
+import org.apache.ambari.shell.model.FocusType;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class HostCommandsTest {
+
+ @InjectMocks
+ private HostCommands hostCommands;
+
+ @Mock
+ private AmbariClient client;
+ @Mock
+ private AmbariContext context;
+
+ @Test
+ public void testFocusHostForValidHost() {
+ when(client.getHostNames()).thenReturn(singletonMap("host1", "HEALTHY"));
+
+ String result = hostCommands.focusHost(new Host("host1"));
+
+ verify(context).setFocus("host1", FocusType.HOST);
+ assertEquals("Focus set to: host1", result);
+ }
+
+ @Test
+ public void testFocusHostForInvalidHost() {
+ when(client.getHostNames()).thenReturn(singletonMap("host3", "HEALTHY"));
+
+ String result = hostCommands.focusHost(new Host("host1"));
+
+ verify(context, times(0)).setFocus("host1", FocusType.HOST);
+ assertEquals("host1 is not a valid host name", result);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/test/java/org/apache/ambari/shell/customization/AmbariPromptTest.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/test/java/org/apache/ambari/shell/customization/AmbariPromptTest.java b/ambari-shell/ambari-groovy-shell/src/test/java/org/apache/ambari/shell/customization/AmbariPromptTest.java
new file mode 100644
index 0000000..ba90d00
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/test/java/org/apache/ambari/shell/customization/AmbariPromptTest.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.shell.customization;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.when;
+
+import org.apache.ambari.shell.model.AmbariContext;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class AmbariPromptTest {
+
+ @InjectMocks
+ private AmbariPrompt prompt;
+
+ @Mock
+ private AmbariContext context;
+
+ @Test
+ public void testGetProviderName() {
+ String result = prompt.getProviderName();
+
+ assertEquals(AmbariPrompt.class.getSimpleName(), result);
+ }
+
+ @Test
+ public void testGetPrompt(){
+ when(context.getPrompt()).thenReturn("prompt");
+
+ String result = prompt.getPrompt();
+
+ assertEquals("prompt", result);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/test/java/org/apache/ambari/shell/model/AmbariContextTest.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/test/java/org/apache/ambari/shell/model/AmbariContextTest.java b/ambari-shell/ambari-groovy-shell/src/test/java/org/apache/ambari/shell/model/AmbariContextTest.java
new file mode 100644
index 0000000..ca9e919
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/test/java/org/apache/ambari/shell/model/AmbariContextTest.java
@@ -0,0 +1,66 @@
+/**
+ * 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.shell.model;
+
+import static org.junit.Assert.assertEquals;
+
+import org.apache.ambari.groovy.client.AmbariClient;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
+
+@RunWith(MockitoJUnitRunner.class)
+public class AmbariContextTest {
+
+ @InjectMocks
+ private AmbariContext ambariContext;
+
+ @Mock
+ private AmbariClient ambariClient;
+
+ @Test
+ public void testGetPromptForRoot() {
+ ReflectionTestUtils.setField(ambariContext, "cluster", "single-node");
+
+ String result = ambariContext.getPrompt();
+
+ assertEquals(FocusType.ROOT.prefix() + ":single-node>", result);
+ }
+
+ @Test
+ public void testGetPromptForRootButNotConnected() {
+ ReflectionTestUtils.setField(ambariContext, "cluster", null);
+
+ String result = ambariContext.getPrompt();
+
+ assertEquals("ambari-shell>", result);
+ }
+
+ @Test
+ public void testGetPromptForFocus() {
+ ReflectionTestUtils.setField(ambariContext, "cluster", "single-node");
+ ReflectionTestUtils.setField(ambariContext, "focus", new Focus("target", FocusType.HOST));
+
+ String result = ambariContext.getPrompt();
+
+ assertEquals(String.format("%s:%s>", FocusType.HOST.prefix(), "target"), result);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/test/java/org/apache/ambari/shell/support/TableRendererTest.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/test/java/org/apache/ambari/shell/support/TableRendererTest.java b/ambari-shell/ambari-groovy-shell/src/test/java/org/apache/ambari/shell/support/TableRendererTest.java
new file mode 100644
index 0000000..e576390
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/test/java/org/apache/ambari/shell/support/TableRendererTest.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.shell.support;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.io.IOUtils;
+import org.junit.Test;
+
+public class TableRendererTest {
+
+ @Test
+ public void testRenderMultiValueMap() throws IOException {
+ Map<String, List<String>> map = new HashMap<String, List<String>>();
+ map.put("HDFS", Collections.singletonList("DATANODE"));
+ map.put("MAPREDUCE2", Collections.singletonList("HISTORYSERVER"));
+ map.put("ZOOKEEPER", Collections.singletonList("ZOOKEEPER_SERVER"));
+ assertEquals(IOUtils.toString(new FileInputStream(new File("src/test/resources/2columns"))),
+ TableRenderer.renderMultiValueMap(map, "SERVICE", "COMPONENT"));
+ }
+
+ @Test
+ public void testRenderMapValueMap() throws IOException {
+ Map<String, Map<String, String>> map = new HashMap<String, Map<String, String>>();
+ map.put("HDFS", Collections.singletonMap("DATANODE", "STARTED"));
+ map.put("MAPREDUCE2", Collections.singletonMap("HISTORYSERVER", "STARTED"));
+ map.put("ZOOKEEPER", Collections.singletonMap("ZOOKEEPER_SERVER", "INSTALLED"));
+ assertEquals(IOUtils.toString(new FileInputStream(new File("src/test/resources/3columns"))),
+ TableRenderer.renderMapValueMap(map, "SERVICE", "COMPONENT", "STATE"));
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/test/resources/2columns
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/test/resources/2columns b/ambari-shell/ambari-groovy-shell/src/test/resources/2columns
new file mode 100644
index 0000000..190771b
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/test/resources/2columns
@@ -0,0 +1,5 @@
+ SERVICE COMPONENT
+ ---------- ----------------
+ ZOOKEEPER ZOOKEEPER_SERVER
+ MAPREDUCE2 HISTORYSERVER
+ HDFS DATANODE
http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/test/resources/3columns
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/test/resources/3columns b/ambari-shell/ambari-groovy-shell/src/test/resources/3columns
new file mode 100644
index 0000000..127a414
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/test/resources/3columns
@@ -0,0 +1,5 @@
+ SERVICE COMPONENT STATE
+ ---------- ---------------- ---------
+ ZOOKEEPER ZOOKEEPER_SERVER INSTALLED
+ MAPREDUCE2 HISTORYSERVER STARTED
+ HDFS DATANODE STARTED
http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/test/resources/testBlueprint.json
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/test/resources/testBlueprint.json b/ambari-shell/ambari-groovy-shell/src/test/resources/testBlueprint.json
new file mode 100644
index 0000000..971c46d
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/test/resources/testBlueprint.json
@@ -0,0 +1,48 @@
+{
+ "host_groups" : [
+ {
+ "name" : "host_group_1",
+ "components" : [
+ {
+ "name" : "NAMENODE"
+ },
+ {
+ "name" : "SECONDARY_NAMENODE"
+ },
+ {
+ "name" : "DATANODE"
+ },
+ {
+ "name" : "HDFS_CLIENT"
+ },
+ {
+ "name" : "RESOURCEMANAGER"
+ },
+ {
+ "name" : "NODEMANAGER"
+ },
+ {
+ "name" : "YARN_CLIENT"
+ },
+ {
+ "name" : "HISTORYSERVER"
+ },
+ {
+ "name" : "MAPREDUCE2_CLIENT"
+ },
+ {
+ "name" : "ZOOKEEPER_SERVER"
+ },
+ {
+ "name" : "ZOOKEEPER_CLIENT"
+ }
+ ],
+ "cardinality" : "1"
+ }
+ ],
+ "Blueprints" : {
+ "blueprint_name" : "single-node-hdfs-yarn",
+ "stack_name" : "HDP",
+ "stack_version" : "2.0"
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-python-shell/conf/unix/ambari-shell
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-python-shell/conf/unix/ambari-shell b/ambari-shell/ambari-python-shell/conf/unix/ambari-shell
new file mode 100644
index 0000000..b6109fe
--- /dev/null
+++ b/ambari-shell/ambari-python-shell/conf/unix/ambari-shell
@@ -0,0 +1,62 @@
+#!/usr/bin/env bash
+
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific
+
+
+# Because Ambari rpm unpacks modules here on all systems
+PARAM="$@"
+export PYTHONPATH=/usr/lib/python2.6/site-packages:$PYTHONPATH
+SHELL_SCRIPT=/usr/lib/python2.6/site-packages/ambari_shell/ambari_shell.py
+OK=1
+NOTOK=0
+if [ -a /usr/bin/python2.7 ] && [ -z "$PYTHON" ]; then
+ PYTHON=/usr/bin/python2.7
+fi
+
+if [ -a /usr/bin/python2.6 ] && [ -z "$PYTHON" ]; then
+ PYTHON=/usr/bin/python2.6
+fi
+
+if [ "x$PYTHON" == "x" ]; then
+ PYTHON=/usr/bin/python
+fi
+
+export PYTHON=$PYTHON
+
+
+
+# check for version
+check_python_version ()
+{
+ echo "Verifying Python version compatibility..."
+ majversion=`$PYTHON -V 2>&1 | awk '{print $2}' | cut -d'.' -f1`
+ minversion=`$PYTHON -V 2>&1 | awk '{print $2}' | cut -d'.' -f2`
+ numversion=$(( 10 * $majversion + $minversion))
+ if (( $numversion < 26 )); then
+ echo "ERROR: Found Python version $majversion.$minversion. Ambari Agent requires Python version > 2.6"
+ return $NOTOK
+ fi
+ echo "Using python " $PYTHON
+ return $OK
+}
+
+retcode=0
+check_python_version
+if [ "$?" -eq "$NOTOK" ]; then
+ exit -1
+fi
+$PYTHON $SHELL_SCRIPT $PARAM
+
+exit $retcode
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-python-shell/conf/unix/ambari-shell.ini
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-python-shell/conf/unix/ambari-shell.ini b/ambari-shell/ambari-python-shell/conf/unix/ambari-shell.ini
new file mode 100644
index 0000000..9ac158d
--- /dev/null
+++ b/ambari-shell/ambari-python-shell/conf/unix/ambari-shell.ini
@@ -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
+
+[python_shell]
+loglevel=debug
+log_folder=/var/log/ambari-shell/
+cliplugin_folder=/root/workspace/python_shell/plugins
+default_plugin_folder=/usr/lib/python2.6/site-packages/ambari_shell/plugins
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-python-shell/pom.xml
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-python-shell/pom.xml b/ambari-shell/ambari-python-shell/pom.xml
new file mode 100644
index 0000000..881f745
--- /dev/null
+++ b/ambari-shell/ambari-python-shell/pom.xml
@@ -0,0 +1,237 @@
+<?xml version="1.0"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <!--
+ 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 Licenseam for the specific language governing permissions and
+ limitations under the License.
+-->
+ <parent>
+ <groupId>org.apache.ambari</groupId>
+ <artifactId>ambari-shell</artifactId>
+ <version>1.3.0-SNAPSHOT</version>
+ <relativePath>../../ambari-shell</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.apache.ambari</groupId>
+ <artifactId>ambari-python-shell</artifactId>
+ <packaging>pom</packaging>
+ <version>1.3.0-SNAPSHOT</version>
+ <name>Ambari Python Shell</name>
+ <description>Ambari Python Shell</description>
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <final.name>${project.artifactId}-${project.version}</final.name>
+ <package.release>1</package.release>
+ <package.prefix>/usr</package.prefix>
+ <package.log.dir>/var/log/ambari-shell</package.log.dir>
+ <package.pid.dir>/var/run/ambari-shell</package.pid.dir>
+ <skipTests>false</skipTests>
+ <install.dir>/usr/lib/python2.6/site-packages/ambari_shell</install.dir>
+ <lib.dir>/usr/lib/ambari-shell/lib</lib.dir>
+ <python.ver>python >= 2.6</python.ver>
+ <deb.python.ver>python (>= 2.6)</deb.python.ver>
+ <deb.architecture>amd64</deb.architecture>
+ <deb.dependency.list>openssl, zlibc, ${deb.python.ver}</deb.dependency.list>
+ </properties>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.0</version>
+ </plugin>
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <configuration>
+ <tarLongFileMode>gnu</tarLongFileMode>
+ <descriptors>
+ <descriptor>src/packages/tarball/all.xml</descriptor>
+ </descriptors>
+ </configuration>
+ <executions>
+ <execution>
+ <id>build-tarball</id>
+ <phase>prepare-package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>exec-maven-plugin</artifactId>
+ <version>1.2</version>
+ <executions>
+ <execution>
+ <configuration>
+ <executable>${project.basedir}/../../ambari-common/src/main/unix/ambari-python-wrap</executable>
+ <workingDirectory>src/test/python</workingDirectory>
+ <arguments>
+ <argument>unitTests.py</argument>
+ </arguments>
+ <environmentVariables>
+ <PYTHONPATH>${project.basedir}/../../ambari-common/src/test/python:${project.basedir}/../../ambari-client/python-client/src/test/python:${project.basedir}/../../ambari-client/python-client/src/main/python/ambari_client:${project.basedir}/src/main/python/ambari_shell:${project.basedir}/src/test/python/utils:$PYTHONPATH</PYTHONPATH>
+ </environmentVariables>
+ <skip>${skipTests}</skip>
+ </configuration>
+ <id>python-test</id>
+ <phase>test</phase>
+ <goals>
+ <goal>exec</goal>
+ </goals>
+ </execution>
+ <execution>
+ <configuration>
+ <executable>${project.basedir}/../../ambari-common/src/main/unix/ambari-python-wrap</executable>
+ <workingDirectory>target/ambari-python-shell-${project.version}</workingDirectory>
+ <arguments>
+ <argument>${project.basedir}/src/main/python/setup.py</argument>
+ <argument>clean</argument>
+ <argument>bdist_dumb</argument>
+ </arguments>
+ <environmentVariables>
+ <PYTHONPATH>target/python-client-${project.version}:$PYTHONPATH</PYTHONPATH>
+ </environmentVariables>
+ </configuration>
+ <id>python-package</id>
+ <phase>package</phase>
+ <goals>
+ <goal>exec</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>rpm-maven-plugin</artifactId>
+ <version>2.0.1</version>
+ <executions>
+ <execution>
+ <phase>none</phase>
+ <goals>
+ <goal>rpm</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <copyright>2012, Apache Software Foundation</copyright>
+ <group>Development</group>
+ <description>Maven Recipe: RPM Package.</description>
+ <requires>
+ <require>openssl</require>
+ <require>zlib</require>
+ <require>${python.ver}</require>
+ </requires>
+ <needarch>x86_64</needarch>
+ <autoRequires>false</autoRequires>
+ <mappings>
+ <mapping>
+ <directory>/etc/ambari-shell/conf</directory>
+ <filemode>755</filemode>
+ <username>root</username>
+ <groupname>root</groupname>
+ <sources>
+ <source>
+ <location>conf/unix/ambari-shell.ini</location>
+ </source>
+ </sources>
+ </mapping>
+ <mapping>
+ <directory>/usr/sbin</directory>
+ <filemode>755</filemode>
+ <username>root</username>
+ <groupname>root</groupname>
+ <directoryIncluded>false</directoryIncluded>
+ <sources>
+ <source>
+ <location>conf/unix/ambari-shell</location>
+ <filter>true</filter>
+ </source>
+ </sources>
+ </mapping>
+ <mapping>
+ <directory>${package.log.dir}</directory>
+ <filemode>755</filemode>
+ <username>root</username>
+ <groupname>root</groupname>
+ </mapping>
+ <mapping>
+ <directory>${install.dir}</directory>
+ <sources>
+ <source>
+ <location>${project.build.directory}/${project.artifactId}-${project.version}/ambari_shell</location>
+ </source>
+ </sources>
+ </mapping>
+ </mappings>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.rat</groupId>
+ <artifactId>apache-rat-plugin</artifactId>
+ <configuration>
+ <excludes>
+ <exclude>src/examples/*</exclude>
+ <exclude>src/test/python/dummy*.txt</exclude>
+ <exclude>src/main/python/ambari_client/imports.txt</exclude>
+ <exclude>src/main/puppet/modules/stdlib/**</exclude>
+ <exclude>**/*.erb</exclude>
+ <exclude>**/*.json</exclude>
+ </excludes>
+ </configuration>
+ <executions>
+ <execution>
+ <phase>test</phase>
+ <goals>
+ <goal>check</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.vafer</groupId>
+ <artifactId>jdeb</artifactId>
+ <version>1.0.1</version>
+ <executions>
+ <execution>
+ <phase>none</phase>
+ <goals>
+ <goal>jdeb</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <controlDir>${basedir}/src/main/package/deb/control</controlDir>
+ <deb>${basedir}/target/${artifactId}_${package-version}-${package-release}.deb</deb>
+ <dataSet>
+ <data>
+ <src>${project.build.directory}/${project.artifactId}-${project.version}/ambari_shell</src>
+ <type>directory</type>
+ <mapper>
+ <type>perm</type>
+ <prefix>${install.dir}</prefix>
+ </mapper>
+ </data>
+ </dataSet>
+ </configuration>
+ </plugin>
+ </plugins>
+ <extensions>
+ <extension>
+ <groupId>org.apache.maven.wagon</groupId>
+ <artifactId>wagon-ssh-external</artifactId>
+ </extension>
+ </extensions>
+ </build>
+</project>
http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-python-shell/src/main/package/deb/control/control
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-python-shell/src/main/package/deb/control/control b/ambari-shell/ambari-python-shell/src/main/package/deb/control/control
new file mode 100644
index 0000000..40cd855
--- /dev/null
+++ b/ambari-shell/ambari-python-shell/src/main/package/deb/control/control
@@ -0,0 +1,22 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License
+Package: [[artifactId]]
+Version: [[package-version]]-[[package-release]]
+Section: [[deb.section]]
+Priority: [[deb.priority]]
+Depends: [[deb.dependency.list]]
+Architecture: [[deb.architecture]]
+Description: [[description]]
+Maintainer: [[deb.publisher]]
http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-python-shell/src/main/package/deb/control/postinst
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-python-shell/src/main/package/deb/control/postinst b/ambari-shell/ambari-python-shell/src/main/package/deb/control/postinst
new file mode 100644
index 0000000..21a01fa
--- /dev/null
+++ b/ambari-shell/ambari-python-shell/src/main/package/deb/control/postinst
@@ -0,0 +1,15 @@
+#!/bin/bash
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License
http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-python-shell/src/main/package/deb/control/postrm
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-python-shell/src/main/package/deb/control/postrm b/ambari-shell/ambari-python-shell/src/main/package/deb/control/postrm
new file mode 100644
index 0000000..21a01fa
--- /dev/null
+++ b/ambari-shell/ambari-python-shell/src/main/package/deb/control/postrm
@@ -0,0 +1,15 @@
+#!/bin/bash
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License
http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-python-shell/src/main/package/deb/control/posttrm
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-python-shell/src/main/package/deb/control/posttrm b/ambari-shell/ambari-python-shell/src/main/package/deb/control/posttrm
new file mode 100644
index 0000000..21a01fa
--- /dev/null
+++ b/ambari-shell/ambari-python-shell/src/main/package/deb/control/posttrm
@@ -0,0 +1,15 @@
+#!/bin/bash
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License
http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-python-shell/src/main/package/deb/control/preinst
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-python-shell/src/main/package/deb/control/preinst b/ambari-shell/ambari-python-shell/src/main/package/deb/control/preinst
new file mode 100644
index 0000000..21a01fa
--- /dev/null
+++ b/ambari-shell/ambari-python-shell/src/main/package/deb/control/preinst
@@ -0,0 +1,15 @@
+#!/bin/bash
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License
http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-python-shell/src/main/package/deb/control/prerm
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-python-shell/src/main/package/deb/control/prerm b/ambari-shell/ambari-python-shell/src/main/package/deb/control/prerm
new file mode 100644
index 0000000..21a01fa
--- /dev/null
+++ b/ambari-shell/ambari-python-shell/src/main/package/deb/control/prerm
@@ -0,0 +1,15 @@
+#!/bin/bash
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License
http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/__init__.py
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/__init__.py b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/__init__.py
new file mode 100644
index 0000000..278df2e
--- /dev/null
+++ b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/__init__.py
@@ -0,0 +1,16 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.