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:49 UTC

[1/4] AMBARI-6176. Integrate python shell into Ambari-shell module(subin)

Repository: ambari
Updated Branches:
  refs/heads/trunk 2ff28495a -> c8eceafc9


http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/src/main/java/org/apache/ambari/shell/commands/HostCommands.java
----------------------------------------------------------------------
diff --git a/ambari-shell/src/main/java/org/apache/ambari/shell/commands/HostCommands.java b/ambari-shell/src/main/java/org/apache/ambari/shell/commands/HostCommands.java
deleted file mode 100644
index dd3c775..0000000
--- a/ambari-shell/src/main/java/org/apache/ambari/shell/commands/HostCommands.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.ambari.shell.commands;
-
-import static org.apache.ambari.shell.support.TableRenderer.renderSingleMap;
-
-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.springframework.beans.factory.annotation.Autowired;
-import org.springframework.shell.core.CommandMarker;
-import org.springframework.shell.core.annotation.CliAvailabilityIndicator;
-import org.springframework.shell.core.annotation.CliCommand;
-import org.springframework.shell.core.annotation.CliOption;
-import org.springframework.stereotype.Component;
-
-/**
- * Host related commands used in the shell.
- *
- * @see org.apache.ambari.groovy.client.AmbariClient
- */
-@Component
-public class HostCommands implements CommandMarker {
-
-  private AmbariClient client;
-  private AmbariContext context;
-
-  @Autowired
-  public HostCommands(AmbariClient client, AmbariContext context) {
-    this.client = client;
-    this.context = context;
-  }
-
-  /**
-   * Checks whether the host list command is available or not.
-   *
-   * @return true if available false otherwise
-   */
-  @CliAvailabilityIndicator("host list")
-  public boolean isHostsCommandAvailable() {
-    return true;
-  }
-
-  /**
-   * Prints the available hosts of the Ambari Server.
-   *
-   * @return host list
-   */
-  @CliCommand(value = "host list", help = "Lists the available hosts")
-  public String hosts() {
-    return client.showHostList();
-  }
-
-  /**
-   * Checks whether the host focus command is available or not.
-   *
-   * @return true if available false otherwise
-   */
-  @CliAvailabilityIndicator("host focus")
-  public boolean isFocusHostCommandAvailable() {
-    return context.isConnectedToCluster();
-  }
-
-  /**
-   * Sets the focus to the specified host.
-   *
-   * @param host the host to set the focus to
-   * @return status message
-   */
-  @CliCommand(value = "host focus", help = "Sets the useHost to the specified host")
-  public String focusHost(
-    @CliOption(key = "host", mandatory = true, help = "hostname") Host host) {
-    String message;
-    String hostName = host.getName();
-    if (client.getHostNames().keySet().contains(hostName)) {
-      context.setFocus(hostName, FocusType.HOST);
-      message = "Focus set to: " + hostName;
-    } else {
-      message = hostName + " is not a valid host name";
-    }
-    return message;
-  }
-
-  /**
-   * Checks whether the host components command is available or not.
-   *
-   * @return true if available false otherwise
-   */
-  @CliAvailabilityIndicator("host components")
-  public boolean isHostComponentsCommandAvailable() {
-    return context.isFocusOnHost();
-  }
-
-  /**
-   * Prints the components which belongs to the host being focused on.
-   *
-   * @return list of host components
-   */
-  @CliCommand(value = "host components", help = "Lists the components assigned to the selected host")
-  public String hostComponents() {
-    return renderSingleMap(client.getHostComponentsMap(context.getFocusValue()), "COMPONENT", "STATE");
-  }
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/src/main/java/org/apache/ambari/shell/completion/Blueprint.java
----------------------------------------------------------------------
diff --git a/ambari-shell/src/main/java/org/apache/ambari/shell/completion/Blueprint.java b/ambari-shell/src/main/java/org/apache/ambari/shell/completion/Blueprint.java
deleted file mode 100644
index 4eec7b1..0000000
--- a/ambari-shell/src/main/java/org/apache/ambari/shell/completion/Blueprint.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.ambari.shell.completion;
-
-/**
- * Wrapper class for TAB completion to blueprint names.
- */
-public class Blueprint {
-
-  private final String name;
-
-  public Blueprint(String name) {
-    this.name = name;
-  }
-
-  public String getName() {
-    return name;
-  }
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/src/main/java/org/apache/ambari/shell/completion/Host.java
----------------------------------------------------------------------
diff --git a/ambari-shell/src/main/java/org/apache/ambari/shell/completion/Host.java b/ambari-shell/src/main/java/org/apache/ambari/shell/completion/Host.java
deleted file mode 100644
index f64e97b..0000000
--- a/ambari-shell/src/main/java/org/apache/ambari/shell/completion/Host.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.ambari.shell.completion;
-
-/**
- * Wrapper class for TAB completion to host names.
- */
-public class Host {
-
-  private final String name;
-
-  public Host(String name) {
-    this.name = name;
-  }
-
-  public String getName() {
-    return name;
-  }
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/src/main/java/org/apache/ambari/shell/configuration/ConverterConfiguration.java
----------------------------------------------------------------------
diff --git a/ambari-shell/src/main/java/org/apache/ambari/shell/configuration/ConverterConfiguration.java b/ambari-shell/src/main/java/org/apache/ambari/shell/configuration/ConverterConfiguration.java
deleted file mode 100644
index 049c52f..0000000
--- a/ambari-shell/src/main/java/org/apache/ambari/shell/configuration/ConverterConfiguration.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.ambari.shell.configuration;
-
-import org.apache.ambari.groovy.client.AmbariClient;
-import org.apache.ambari.shell.converter.BlueprintConverter;
-import org.apache.ambari.shell.converter.HostConverter;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.shell.converters.AvailableCommandsConverter;
-import org.springframework.shell.converters.BigDecimalConverter;
-import org.springframework.shell.converters.BigIntegerConverter;
-import org.springframework.shell.converters.BooleanConverter;
-import org.springframework.shell.converters.CharacterConverter;
-import org.springframework.shell.converters.DateConverter;
-import org.springframework.shell.converters.DoubleConverter;
-import org.springframework.shell.converters.EnumConverter;
-import org.springframework.shell.converters.FloatConverter;
-import org.springframework.shell.converters.IntegerConverter;
-import org.springframework.shell.converters.LocaleConverter;
-import org.springframework.shell.converters.LongConverter;
-import org.springframework.shell.converters.ShortConverter;
-import org.springframework.shell.converters.SimpleFileConverter;
-import org.springframework.shell.converters.StaticFieldConverterImpl;
-import org.springframework.shell.converters.StringConverter;
-import org.springframework.shell.core.Converter;
-
-/**
- * Configures the converters used by the shell.
- */
-@Configuration
-public class ConverterConfiguration {
-
-  @Autowired
-  private AmbariClient client;
-
-  @Bean
-  Converter simpleFileConverter() {
-    return new SimpleFileConverter();
-  }
-
-  @Bean
-  Converter stringConverter() {
-    return new StringConverter();
-  }
-
-  @Bean
-  Converter availableCommandsConverter() {
-    return new AvailableCommandsConverter();
-  }
-
-  @Bean
-  Converter bigDecimalConverter() {
-    return new BigDecimalConverter();
-  }
-
-  @Bean
-  Converter bigIntegerConverter() {
-    return new BigIntegerConverter();
-  }
-
-  @Bean
-  Converter booleanConverter() {
-    return new BooleanConverter();
-  }
-
-  @Bean
-  Converter characterConverter() {
-    return new CharacterConverter();
-  }
-
-  @Bean
-  Converter dateConverter() {
-    return new DateConverter();
-  }
-
-  @Bean
-  Converter doubleConverter() {
-    return new DoubleConverter();
-  }
-
-  @Bean
-  Converter enumConverter() {
-    return new EnumConverter();
-  }
-
-  @Bean
-  Converter floatConverter() {
-    return new FloatConverter();
-  }
-
-  @Bean
-  Converter integerConverter() {
-    return new IntegerConverter();
-  }
-
-  @Bean
-  Converter localeConverter() {
-    return new LocaleConverter();
-  }
-
-  @Bean
-  Converter longConverter() {
-    return new LongConverter();
-  }
-
-  @Bean
-  Converter shortConverter() {
-    return new ShortConverter();
-  }
-
-  @Bean
-  Converter staticFieldConverterImpl() {
-    return new StaticFieldConverterImpl();
-  }
-
-  @Bean
-  Converter blueprintConverter() {
-    return new BlueprintConverter(client);
-  }
-
-  @Bean
-  Converter hostConverter() {
-    return new HostConverter(client);
-  }
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/src/main/java/org/apache/ambari/shell/configuration/ShellConfiguration.java
----------------------------------------------------------------------
diff --git a/ambari-shell/src/main/java/org/apache/ambari/shell/configuration/ShellConfiguration.java b/ambari-shell/src/main/java/org/apache/ambari/shell/configuration/ShellConfiguration.java
deleted file mode 100644
index 4c493b0..0000000
--- a/ambari-shell/src/main/java/org/apache/ambari/shell/configuration/ShellConfiguration.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.ambari.shell.configuration;
-
-import org.apache.ambari.groovy.client.AmbariClient;
-import org.codehaus.jackson.map.ObjectMapper;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
-import org.springframework.scheduling.concurrent.ThreadPoolExecutorFactoryBean;
-import org.springframework.shell.CommandLine;
-import org.springframework.shell.SimpleShellCommandLineOptions;
-import org.springframework.shell.commands.ExitCommands;
-import org.springframework.shell.commands.HelpCommands;
-import org.springframework.shell.commands.ScriptCommands;
-import org.springframework.shell.commands.VersionCommands;
-import org.springframework.shell.core.CommandMarker;
-import org.springframework.shell.core.JLineShellComponent;
-import org.springframework.shell.plugin.HistoryFileNameProvider;
-import org.springframework.shell.plugin.support.DefaultHistoryFileNameProvider;
-
-/**
- * Spring bean definitions.
- */
-@Configuration
-public class ShellConfiguration {
-
-  @Value("${ambari.host:localhost}")
-  private String host;
-
-  @Value("${ambari.port:8080}")
-  private String port;
-
-  @Value("${ambari.user:admin}")
-  private String user;
-
-  @Value("${ambari.password:admin}")
-  private String password;
-
-  @Value("${cmdfile:}")
-  private String cmdFile;
-
-  @Bean
-  AmbariClient createAmbariClient() {
-    return new AmbariClient(host, port, user, password);
-  }
-
-  @Bean
-  static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
-    return new PropertySourcesPlaceholderConfigurer();
-  }
-
-  @Bean
-  HistoryFileNameProvider defaultHistoryFileNameProvider() {
-    return new DefaultHistoryFileNameProvider();
-  }
-
-  @Bean(name = "shell")
-  JLineShellComponent shell() {
-    return new JLineShellComponent();
-  }
-
-  @Bean
-  CommandLine commandLine() throws Exception {
-    String[] args = cmdFile.length() > 0 ? new String[]{"--cmdfile", cmdFile} : new String[0];
-    return SimpleShellCommandLineOptions.parseCommandLine(args);
-  }
-
-  @Bean
-  ThreadPoolExecutorFactoryBean getThreadPoolExecutorFactoryBean() {
-    return new ThreadPoolExecutorFactoryBean();
-  }
-
-  @Bean
-  ObjectMapper getObjectMapper() {
-    return new ObjectMapper();
-  }
-
-  @Bean
-  CommandMarker exitCommand() {
-    return new ExitCommands();
-  }
-
-  @Bean
-  CommandMarker versionCommands() {
-    return new VersionCommands();
-  }
-
-  @Bean
-  CommandMarker helpCommands() {
-    return new HelpCommands();
-  }
-
-  @Bean
-  CommandMarker scriptCommands() {
-    return new ScriptCommands();
-  }
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/src/main/java/org/apache/ambari/shell/converter/BlueprintConverter.java
----------------------------------------------------------------------
diff --git a/ambari-shell/src/main/java/org/apache/ambari/shell/converter/BlueprintConverter.java b/ambari-shell/src/main/java/org/apache/ambari/shell/converter/BlueprintConverter.java
deleted file mode 100644
index 7984e7f..0000000
--- a/ambari-shell/src/main/java/org/apache/ambari/shell/converter/BlueprintConverter.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.ambari.shell.converter;
-
-import java.util.List;
-import java.util.Set;
-
-import org.apache.ambari.groovy.client.AmbariClient;
-import org.apache.ambari.shell.completion.Blueprint;
-import org.springframework.shell.core.Completion;
-import org.springframework.shell.core.Converter;
-import org.springframework.shell.core.MethodTarget;
-
-/**
- * Converter used to complete blueprint names.
- */
-public class BlueprintConverter implements Converter<Blueprint> {
-
-  private AmbariClient client;
-
-  public BlueprintConverter(AmbariClient client) {
-    this.client = client;
-  }
-
-  @Override
-  public boolean supports(Class<?> type, String optionContext) {
-    return Blueprint.class.isAssignableFrom(type);
-  }
-
-  @Override
-  public Blueprint convertFromText(String value, Class<?> targetType, String optionContext) {
-    return new Blueprint(value);
-  }
-
-  @Override
-  public boolean getAllPossibleValues(List<Completion> completions, Class<?> targetType, String existingData, String optionContext, MethodTarget target) {
-    Set<String> blueprints = client.getBlueprintsMap().keySet();
-    for (String blueprint : blueprints) {
-      completions.add(new Completion(blueprint));
-    }
-    return true;
-  }
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/src/main/java/org/apache/ambari/shell/converter/HostConverter.java
----------------------------------------------------------------------
diff --git a/ambari-shell/src/main/java/org/apache/ambari/shell/converter/HostConverter.java b/ambari-shell/src/main/java/org/apache/ambari/shell/converter/HostConverter.java
deleted file mode 100644
index 39aa6e9..0000000
--- a/ambari-shell/src/main/java/org/apache/ambari/shell/converter/HostConverter.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.ambari.shell.converter;
-
-import java.util.List;
-import java.util.Set;
-
-import org.apache.ambari.groovy.client.AmbariClient;
-import org.apache.ambari.shell.completion.Host;
-import org.springframework.shell.core.Completion;
-import org.springframework.shell.core.Converter;
-import org.springframework.shell.core.MethodTarget;
-
-/**
- * Converter used to complete host names.
- */
-public class HostConverter implements Converter<Host> {
-
-  private AmbariClient client;
-
-  public HostConverter(AmbariClient client) {
-    this.client = client;
-  }
-
-  @Override
-  public boolean supports(Class<?> type, String optionContext) {
-    return Host.class.isAssignableFrom(type);
-  }
-
-  @Override
-  public Host convertFromText(String value, Class<?> targetType, String optionContext) {
-    return new Host(value);
-  }
-
-  @Override
-  public boolean getAllPossibleValues(List<Completion> completions, Class<?> targetType, String existingData, String optionContext, MethodTarget target) {
-    Set<String> hosts = client.getHostNames().keySet();
-    for (String host : hosts) {
-      completions.add(new Completion(host));
-    }
-    return true;
-  }
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/src/main/java/org/apache/ambari/shell/customization/AmbariBanner.java
----------------------------------------------------------------------
diff --git a/ambari-shell/src/main/java/org/apache/ambari/shell/customization/AmbariBanner.java b/ambari-shell/src/main/java/org/apache/ambari/shell/customization/AmbariBanner.java
deleted file mode 100644
index f97ef59..0000000
--- a/ambari-shell/src/main/java/org/apache/ambari/shell/customization/AmbariBanner.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.ambari.shell.customization;
-
-import org.springframework.shell.plugin.BannerProvider;
-import org.springframework.stereotype.Component;
-
-import com.github.lalyos.jfiglet.FigletFont;
-
-/**
- * Prints the banner when the user starts the shell.
- */
-@Component
-public class AmbariBanner implements BannerProvider {
-
-  @Override
-  public String getProviderName() {
-    return "AmbariShell";
-  }
-
-  @Override
-  public String getBanner() {
-    return FigletFont.convertOneLine("AmbariShell");
-  }
-
-  @Override
-  public String getVersion() {
-    return getClass().getPackage().getImplementationVersion();
-  }
-
-  @Override
-  public String getWelcomeMessage() {
-    return "Welcome to Ambari Shell. For command and param completion press TAB, for assistance type 'hint'.";
-  }
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/src/main/java/org/apache/ambari/shell/customization/AmbariHistory.java
----------------------------------------------------------------------
diff --git a/ambari-shell/src/main/java/org/apache/ambari/shell/customization/AmbariHistory.java b/ambari-shell/src/main/java/org/apache/ambari/shell/customization/AmbariHistory.java
deleted file mode 100644
index c23fc9a..0000000
--- a/ambari-shell/src/main/java/org/apache/ambari/shell/customization/AmbariHistory.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.ambari.shell.customization;
-
-import org.springframework.shell.plugin.HistoryFileNameProvider;
-import org.springframework.stereotype.Component;
-
-/**
- * Specifies the name of the Ambari command log. Later this log can be used
- * to re-execute the commands with either the --cmdfile option at startup
- * or with the script --file command.
- */
-@Component
-public class AmbariHistory implements HistoryFileNameProvider {
-
-  @Override
-  public String getHistoryFileName() {
-    return "ambari-log.ash";
-  }
-
-  @Override
-  public String getProviderName() {
-    return "AmbariShell";
-  }
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/src/main/java/org/apache/ambari/shell/customization/AmbariPrompt.java
----------------------------------------------------------------------
diff --git a/ambari-shell/src/main/java/org/apache/ambari/shell/customization/AmbariPrompt.java b/ambari-shell/src/main/java/org/apache/ambari/shell/customization/AmbariPrompt.java
deleted file mode 100644
index b91e76e..0000000
--- a/ambari-shell/src/main/java/org/apache/ambari/shell/customization/AmbariPrompt.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.ambari.shell.customization;
-
-import org.apache.ambari.shell.model.AmbariContext;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.shell.plugin.PromptProvider;
-import org.springframework.stereotype.Component;
-
-/**
- * Manages the text of the shell's prompt.
- */
-@Component
-public class AmbariPrompt implements PromptProvider {
-
-  @Autowired
-  private AmbariContext context;
-
-  @Override
-  public String getProviderName() {
-    return AmbariPrompt.class.getSimpleName();
-  }
-
-  @Override
-  public String getPrompt() {
-    return context.getPrompt();
-  }
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/src/main/java/org/apache/ambari/shell/flash/AbstractFlash.java
----------------------------------------------------------------------
diff --git a/ambari-shell/src/main/java/org/apache/ambari/shell/flash/AbstractFlash.java b/ambari-shell/src/main/java/org/apache/ambari/shell/flash/AbstractFlash.java
deleted file mode 100644
index 58abb75..0000000
--- a/ambari-shell/src/main/java/org/apache/ambari/shell/flash/AbstractFlash.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-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/src/main/java/org/apache/ambari/shell/flash/FlashService.java
----------------------------------------------------------------------
diff --git a/ambari-shell/src/main/java/org/apache/ambari/shell/flash/FlashService.java b/ambari-shell/src/main/java/org/apache/ambari/shell/flash/FlashService.java
deleted file mode 100644
index 78977a6..0000000
--- a/ambari-shell/src/main/java/org/apache/ambari/shell/flash/FlashService.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-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/src/main/java/org/apache/ambari/shell/flash/FlashType.java
----------------------------------------------------------------------
diff --git a/ambari-shell/src/main/java/org/apache/ambari/shell/flash/FlashType.java b/ambari-shell/src/main/java/org/apache/ambari/shell/flash/FlashType.java
deleted file mode 100644
index 754a269..0000000
--- a/ambari-shell/src/main/java/org/apache/ambari/shell/flash/FlashType.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-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/src/main/java/org/apache/ambari/shell/flash/InstallProgress.java
----------------------------------------------------------------------
diff --git a/ambari-shell/src/main/java/org/apache/ambari/shell/flash/InstallProgress.java b/ambari-shell/src/main/java/org/apache/ambari/shell/flash/InstallProgress.java
deleted file mode 100644
index 69164ea..0000000
--- a/ambari-shell/src/main/java/org/apache/ambari/shell/flash/InstallProgress.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-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/src/main/java/org/apache/ambari/shell/model/AmbariContext.java
----------------------------------------------------------------------
diff --git a/ambari-shell/src/main/java/org/apache/ambari/shell/model/AmbariContext.java b/ambari-shell/src/main/java/org/apache/ambari/shell/model/AmbariContext.java
deleted file mode 100644
index af45dd6..0000000
--- a/ambari-shell/src/main/java/org/apache/ambari/shell/model/AmbariContext.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-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/src/main/java/org/apache/ambari/shell/model/Focus.java
----------------------------------------------------------------------
diff --git a/ambari-shell/src/main/java/org/apache/ambari/shell/model/Focus.java b/ambari-shell/src/main/java/org/apache/ambari/shell/model/Focus.java
deleted file mode 100644
index b637c87..0000000
--- a/ambari-shell/src/main/java/org/apache/ambari/shell/model/Focus.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-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/src/main/java/org/apache/ambari/shell/model/FocusType.java
----------------------------------------------------------------------
diff --git a/ambari-shell/src/main/java/org/apache/ambari/shell/model/FocusType.java b/ambari-shell/src/main/java/org/apache/ambari/shell/model/FocusType.java
deleted file mode 100644
index 121f7b4..0000000
--- a/ambari-shell/src/main/java/org/apache/ambari/shell/model/FocusType.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-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/src/main/java/org/apache/ambari/shell/model/Hints.java
----------------------------------------------------------------------
diff --git a/ambari-shell/src/main/java/org/apache/ambari/shell/model/Hints.java b/ambari-shell/src/main/java/org/apache/ambari/shell/model/Hints.java
deleted file mode 100644
index 990c832..0000000
--- a/ambari-shell/src/main/java/org/apache/ambari/shell/model/Hints.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-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/src/main/java/org/apache/ambari/shell/support/TableRenderer.java
----------------------------------------------------------------------
diff --git a/ambari-shell/src/main/java/org/apache/ambari/shell/support/TableRenderer.java b/ambari-shell/src/main/java/org/apache/ambari/shell/support/TableRenderer.java
deleted file mode 100644
index 3e5af1f..0000000
--- a/ambari-shell/src/main/java/org/apache/ambari/shell/support/TableRenderer.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-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/src/main/resources/elephant.txt
----------------------------------------------------------------------
diff --git a/ambari-shell/src/main/resources/elephant.txt b/ambari-shell/src/main/resources/elephant.txt
deleted file mode 100644
index f51e284..0000000
--- a/ambari-shell/src/main/resources/elephant.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-                    .-.._
-              __  /`     '.
-           .-'  `/   (   a \
-          /      (    \,_   \
-         /|       '---` |\ =|
-        ` \    /__.-/  /  | |
-           |  / / \ \  \   \_\
-           |__|_|  |_|__\

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/src/test/java/org/apache/ambari/shell/commands/BlueprintCommandsTest.java
----------------------------------------------------------------------
diff --git a/ambari-shell/src/test/java/org/apache/ambari/shell/commands/BlueprintCommandsTest.java b/ambari-shell/src/test/java/org/apache/ambari/shell/commands/BlueprintCommandsTest.java
deleted file mode 100644
index 3c9277c..0000000
--- a/ambari-shell/src/test/java/org/apache/ambari/shell/commands/BlueprintCommandsTest.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-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/src/test/java/org/apache/ambari/shell/commands/ClusterCommandsTest.java
----------------------------------------------------------------------
diff --git a/ambari-shell/src/test/java/org/apache/ambari/shell/commands/ClusterCommandsTest.java b/ambari-shell/src/test/java/org/apache/ambari/shell/commands/ClusterCommandsTest.java
deleted file mode 100644
index 777d05d..0000000
--- a/ambari-shell/src/test/java/org/apache/ambari/shell/commands/ClusterCommandsTest.java
+++ /dev/null
@@ -1,279 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-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/src/test/java/org/apache/ambari/shell/commands/HostCommandsTest.java
----------------------------------------------------------------------
diff --git a/ambari-shell/src/test/java/org/apache/ambari/shell/commands/HostCommandsTest.java b/ambari-shell/src/test/java/org/apache/ambari/shell/commands/HostCommandsTest.java
deleted file mode 100644
index 6ca6d4d..0000000
--- a/ambari-shell/src/test/java/org/apache/ambari/shell/commands/HostCommandsTest.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-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/src/test/java/org/apache/ambari/shell/customization/AmbariPromptTest.java
----------------------------------------------------------------------
diff --git a/ambari-shell/src/test/java/org/apache/ambari/shell/customization/AmbariPromptTest.java b/ambari-shell/src/test/java/org/apache/ambari/shell/customization/AmbariPromptTest.java
deleted file mode 100644
index ba90d00..0000000
--- a/ambari-shell/src/test/java/org/apache/ambari/shell/customization/AmbariPromptTest.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-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/src/test/java/org/apache/ambari/shell/model/AmbariContextTest.java
----------------------------------------------------------------------
diff --git a/ambari-shell/src/test/java/org/apache/ambari/shell/model/AmbariContextTest.java b/ambari-shell/src/test/java/org/apache/ambari/shell/model/AmbariContextTest.java
deleted file mode 100644
index ca9e919..0000000
--- a/ambari-shell/src/test/java/org/apache/ambari/shell/model/AmbariContextTest.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-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/src/test/java/org/apache/ambari/shell/support/TableRendererTest.java
----------------------------------------------------------------------
diff --git a/ambari-shell/src/test/java/org/apache/ambari/shell/support/TableRendererTest.java b/ambari-shell/src/test/java/org/apache/ambari/shell/support/TableRendererTest.java
deleted file mode 100644
index e576390..0000000
--- a/ambari-shell/src/test/java/org/apache/ambari/shell/support/TableRendererTest.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-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/src/test/resources/2columns
----------------------------------------------------------------------
diff --git a/ambari-shell/src/test/resources/2columns b/ambari-shell/src/test/resources/2columns
deleted file mode 100644
index 190771b..0000000
--- a/ambari-shell/src/test/resources/2columns
+++ /dev/null
@@ -1,5 +0,0 @@
-  SERVICE     COMPONENT
-  ----------  ----------------
-  ZOOKEEPER   ZOOKEEPER_SERVER
-  MAPREDUCE2  HISTORYSERVER
-  HDFS        DATANODE

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/src/test/resources/3columns
----------------------------------------------------------------------
diff --git a/ambari-shell/src/test/resources/3columns b/ambari-shell/src/test/resources/3columns
deleted file mode 100644
index 127a414..0000000
--- a/ambari-shell/src/test/resources/3columns
+++ /dev/null
@@ -1,5 +0,0 @@
-  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/src/test/resources/testBlueprint.json
----------------------------------------------------------------------
diff --git a/ambari-shell/src/test/resources/testBlueprint.json b/ambari-shell/src/test/resources/testBlueprint.json
deleted file mode 100644
index 971c46d..0000000
--- a/ambari-shell/src/test/resources/testBlueprint.json
+++ /dev/null
@@ -1,48 +0,0 @@
-{
-  "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


[4/4] git commit: AMBARI-6176. Integrate python shell into Ambari-shell module(subin)

Posted by su...@apache.org.
AMBARI-6176. Integrate python shell into Ambari-shell module(subin)


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

Branch: refs/heads/trunk
Commit: c8eceafc9efc6fa305519f27c21ab51531c0d7cb
Parents: 2ff2849
Author: Subin <su...@apache.org>
Authored: Wed Jul 2 23:03:34 2014 +0530
Committer: Subin <su...@apache.org>
Committed: Wed Jul 2 23:04:34 2014 +0530

----------------------------------------------------------------------
 .../src/main/python/ambari_client/ambari_api.py |  26 +-
 .../python/ambari_client/core/http_client.py    |  13 +-
 .../python/ambari_client/model/blueprint.py     |  53 +++
 .../src/main/python/ambari_client/model/host.py |   7 +-
 .../main/python/ambari_client/model/paths.py    |   2 +
 .../main/python/ambari_client/model/status.py   |  42 +-
 .../main/python/ambari_client/model/utils.py    |  39 +-
 ambari-shell/ambari-groovy-shell/pom.xml        | 142 +++++++
 .../org/apache/ambari/shell/AmbariShell.java    | 111 +++++
 .../ambari/shell/commands/BasicCommands.java    | 207 ++++++++++
 .../shell/commands/BlueprintCommands.java       | 198 +++++++++
 .../ambari/shell/commands/ClusterCommands.java  | 294 +++++++++++++
 .../ambari/shell/commands/ElephantCommand.java  |  53 +++
 .../ambari/shell/commands/HostCommands.java     | 119 ++++++
 .../ambari/shell/completion/Blueprint.java      |  34 ++
 .../apache/ambari/shell/completion/Host.java    |  34 ++
 .../configuration/ConverterConfiguration.java   | 142 +++++++
 .../shell/configuration/ShellConfiguration.java | 114 +++++
 .../shell/converter/BlueprintConverter.java     |  58 +++
 .../ambari/shell/converter/HostConverter.java   |  58 +++
 .../shell/customization/AmbariBanner.java       |  50 +++
 .../shell/customization/AmbariHistory.java      |  40 ++
 .../shell/customization/AmbariPrompt.java       |  43 ++
 .../ambari/shell/flash/AbstractFlash.java       |  66 +++
 .../apache/ambari/shell/flash/FlashService.java |  47 +++
 .../apache/ambari/shell/flash/FlashType.java    |  39 ++
 .../ambari/shell/flash/InstallProgress.java     |  79 ++++
 .../ambari/shell/model/AmbariContext.java       | 159 +++++++
 .../org/apache/ambari/shell/model/Focus.java    |  53 +++
 .../apache/ambari/shell/model/FocusType.java    |  55 +++
 .../org/apache/ambari/shell/model/Hints.java    |  59 +++
 .../ambari/shell/support/TableRenderer.java     | 121 ++++++
 .../src/main/resources/elephant.txt             |   8 +
 .../shell/commands/BlueprintCommandsTest.java   | 128 ++++++
 .../shell/commands/ClusterCommandsTest.java     | 279 +++++++++++++
 .../ambari/shell/commands/HostCommandsTest.java |  66 +++
 .../shell/customization/AmbariPromptTest.java   |  54 +++
 .../ambari/shell/model/AmbariContextTest.java   |  66 +++
 .../ambari/shell/support/TableRendererTest.java |  54 +++
 .../src/test/resources/2columns                 |   5 +
 .../src/test/resources/3columns                 |   5 +
 .../src/test/resources/testBlueprint.json       |  48 +++
 .../ambari-python-shell/conf/unix/ambari-shell  |  62 +++
 .../conf/unix/ambari-shell.ini                  |  19 +
 ambari-shell/ambari-python-shell/pom.xml        | 237 +++++++++++
 .../src/main/package/deb/control/control        |  22 +
 .../src/main/package/deb/control/postinst       |  15 +
 .../src/main/package/deb/control/postrm         |  15 +
 .../src/main/package/deb/control/posttrm        |  15 +
 .../src/main/package/deb/control/preinst        |  15 +
 .../src/main/package/deb/control/prerm          |  15 +
 .../src/main/python/ambari_shell/__init__.py    |  16 +
 .../main/python/ambari_shell/ambari_shell.py    | 412 +++++++++++++++++++
 .../python/ambari_shell/plugins/__init__.py     |  16 +
 .../python/ambari_shell/plugins/blueprint.py    |  21 +
 .../ambari_shell/plugins/connect_cluster.py     |  81 ++++
 .../ambari_shell/plugins/create_cluster.py      |  34 ++
 .../main/python/ambari_shell/plugins/service.py | 125 ++++++
 .../python/ambari_shell/plugins/shell_config.py |  77 ++++
 .../main/python/ambari_shell/plugins/show.py    | 155 +++++++
 .../main/python/ambari_shell/utils/__init__.py  |  16 +
 .../python/ambari_shell/utils/displayutils.py   | 128 ++++++
 .../main/python/ambari_shell/utils/osutils.py   |  69 ++++
 .../python/ambari_shell/utils/pluginutils.py    | 100 +++++
 .../src/main/python/setup.py                    |  40 ++
 .../src/packages/tarball/all.xml                |  34 ++
 ambari-shell/assemblies/client.xml              |  20 +
 ambari-shell/pom.xml                            | 128 ++----
 .../org/apache/ambari/shell/AmbariShell.java    | 111 -----
 .../ambari/shell/commands/BasicCommands.java    | 207 ----------
 .../shell/commands/BlueprintCommands.java       | 198 ---------
 .../ambari/shell/commands/ClusterCommands.java  | 294 -------------
 .../ambari/shell/commands/ElephantCommand.java  |  53 ---
 .../ambari/shell/commands/HostCommands.java     | 119 ------
 .../ambari/shell/completion/Blueprint.java      |  34 --
 .../apache/ambari/shell/completion/Host.java    |  34 --
 .../configuration/ConverterConfiguration.java   | 142 -------
 .../shell/configuration/ShellConfiguration.java | 114 -----
 .../shell/converter/BlueprintConverter.java     |  58 ---
 .../ambari/shell/converter/HostConverter.java   |  58 ---
 .../shell/customization/AmbariBanner.java       |  50 ---
 .../shell/customization/AmbariHistory.java      |  40 --
 .../shell/customization/AmbariPrompt.java       |  43 --
 .../ambari/shell/flash/AbstractFlash.java       |  66 ---
 .../apache/ambari/shell/flash/FlashService.java |  47 ---
 .../apache/ambari/shell/flash/FlashType.java    |  39 --
 .../ambari/shell/flash/InstallProgress.java     |  79 ----
 .../ambari/shell/model/AmbariContext.java       | 159 -------
 .../org/apache/ambari/shell/model/Focus.java    |  53 ---
 .../apache/ambari/shell/model/FocusType.java    |  55 ---
 .../org/apache/ambari/shell/model/Hints.java    |  59 ---
 .../ambari/shell/support/TableRenderer.java     | 121 ------
 ambari-shell/src/main/resources/elephant.txt    |   8 -
 .../shell/commands/BlueprintCommandsTest.java   | 128 ------
 .../shell/commands/ClusterCommandsTest.java     | 279 -------------
 .../ambari/shell/commands/HostCommandsTest.java |  66 ---
 .../shell/customization/AmbariPromptTest.java   |  54 ---
 .../ambari/shell/model/AmbariContextTest.java   |  66 ---
 .../ambari/shell/support/TableRendererTest.java |  54 ---
 ambari-shell/src/test/resources/2columns        |   5 -
 ambari-shell/src/test/resources/3columns        |   5 -
 .../src/test/resources/testBlueprint.json       |  48 ---
 102 files changed, 5039 insertions(+), 3064 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-client/python-client/src/main/python/ambari_client/ambari_api.py
----------------------------------------------------------------------
diff --git a/ambari-client/python-client/src/main/python/ambari_client/ambari_api.py b/ambari-client/python-client/src/main/python/ambari_client/ambari_api.py
index 470db36..a79d907 100644
--- a/ambari-client/python-client/src/main/python/ambari_client/ambari_api.py
+++ b/ambari-client/python-client/src/main/python/ambari_client/ambari_api.py
@@ -18,7 +18,7 @@
 import logging
 from ambari_client.core.http_client import HttpClient
 from ambari_client.core.rest_resource import RestResource
-from ambari_client.model import blueprint, stack, cluster, host
+from ambari_client.model import blueprint, stack, cluster, host, status
 
 __docformat__ = "epytext"
 
@@ -66,6 +66,13 @@ class AmbariClient(RestResource):
             if port is None:
                 port = 8080
 
+        if not http_header:
+            http_header = {'X-Requested-By': 'pythonclient'}
+        elif 'X-Requested-By' not in http_header.keys():
+            http_header.update({'X-Requested-By': 'pythonclient'})
+        else:
+            pass
+
         host_url = "%s://%s:%s/api/v%s" % (protocol, host_name, port, version)
         if client is None:
             client = HttpClient(host_url, user_name, password)
@@ -224,6 +231,15 @@ class AmbariClient(RestResource):
         """
         return cluster._task_status(self, cluster_name, requestid)
 
+    def get_requests(self, cluster_name, noOfrequest=3):
+        """
+        get components from stack
+        @param version: The HDP version.
+        @param service_name: service name
+        @return: A ConfigModel object
+        """
+        return status._get_N_requests(self, cluster_name, noOfrequest)
+
     def get_blueprint(self, blueprint_name=None):
         """
         get blueprint
@@ -232,6 +248,14 @@ class AmbariClient(RestResource):
         """
         return blueprint.get_blueprint(self, blueprint_name)
 
+    def get_cluster_blueprint(self, cluster_name):
+        """
+        get blueprint
+        @param cluster_name:cluster_name name.
+        @return: A BlueprintModel object
+        """
+        return blueprint.get_cluster_blueprint(self, cluster_name)
+
     def delete_blueprint(self, blueprint_name=None):
         """
         get blueprint

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-client/python-client/src/main/python/ambari_client/core/http_client.py
----------------------------------------------------------------------
diff --git a/ambari-client/python-client/src/main/python/ambari_client/core/http_client.py b/ambari-client/python-client/src/main/python/ambari_client/core/http_client.py
index 299b279..72b3b5f 100644
--- a/ambari-client/python-client/src/main/python/ambari_client/core/http_client.py
+++ b/ambari-client/python-client/src/main/python/ambari_client/core/http_client.py
@@ -103,6 +103,13 @@ class HttpClient(object):
         self.c.setopt(pycurl.WRITEFUNCTION, buf.write)
         self.c.setopt(pycurl.SSL_VERIFYPEER, 0)
 
+        # make sure options are reset from previous requests or your GET might
+        # become a DELETE
+        self.c.setopt(pycurl.CUSTOMREQUEST, None)
+        self.c.setopt(pycurl.HTTPGET, 0)
+        self.c.setopt(pycurl.NOBODY, 0)
+        self.c.setopt(pycurl.POST, 0)
+
         LOG.debug("invoke : url = " + str(url))
         # set http_method
         if http_method == "GET":
@@ -121,9 +128,9 @@ class HttpClient(object):
         if http_method in ('POST', 'PUT'):
             LOG.debug("data..........." + str(payload))
             data = json.dumps(payload)
-            #data= data.decode('unicode-escape')
-            #LOG.debug( "after unicode decode")
-            #LOG.debug( data)
+            # data= data.decode('unicode-escape')
+            # LOG.debug( "after unicode decode")
+            # LOG.debug( data)
             data = self._to_bytestring(data)
             LOG.debug("after _to_bytestring")
             LOG.debug(data)

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-client/python-client/src/main/python/ambari_client/model/blueprint.py
----------------------------------------------------------------------
diff --git a/ambari-client/python-client/src/main/python/ambari_client/model/blueprint.py b/ambari-client/python-client/src/main/python/ambari_client/model/blueprint.py
index 8497dc6..e207a6b 100644
--- a/ambari-client/python-client/src/main/python/ambari_client/model/blueprint.py
+++ b/ambari-client/python-client/src/main/python/ambari_client/model/blueprint.py
@@ -15,6 +15,7 @@
 #  limitations under the License.
 
 import logging
+import json
 from ambari_client.model.base_model import BaseModel, ModelList
 from ambari_client.model import paths, utils, status
 
@@ -46,6 +47,33 @@ def get_blueprint(resource_root, blueprint_name):
             "Blueprints")
 
 
+def get_cluster_blueprint(resource_root, cluster_name):
+    """
+    Get all Blueprint
+    @param root_resource: The root Resource .
+    @param name: blueprint_name
+    @return: A list of BlueprintModel objects.
+    """
+    resp = resource_root.get(paths.BLUEPRINT_CLUSTER_PATH % cluster_name)
+    result = json.dumps(resp)
+    resp_dictt = json.loads(result)
+    objects = [
+        utils.ModelUtils.create_model(
+            BlueprintHostModel,
+            x,
+            resource_root,
+            "NO_KEY") for x in resp_dictt['host_groups']]
+    LOG.debug(objects)
+
+    bluep = utils.ModelUtils.create_model(
+        BlueprintModel,
+        resp,
+        resource_root,
+        "Blueprints")
+
+    return bluep, ModelList(objects)
+
+
 def delete_blueprint(resource_root, blueprint_name):
     """
     Delete a blueprint by name
@@ -93,6 +121,31 @@ class BlueprintModel(BaseModel):
         return "<<BlueprintModel>> blueprint_name = %s " % (
             self.blueprint_name)
 
+    def _get_cluster_name(self):
+        if self.clusterRef:
+            return self.clusterRef.cluster_name
+        return None
+
+
+class BlueprintHostModel(BaseModel):
+
+    """
+    The BlueprintHostModel class
+    """
+    RO_ATTR = ('blueprint_name',)
+    RW_ATTR = ('name', 'components', 'cardinality')
+    REF_ATTR = ()
+
+    def __init__(self, resource_root, name, components, cardinality):
+        utils.retain_self_helper(BaseModel, **locals())
+
+    def __str__(self):
+        return "<<BlueprintHostModel>> name = %s ,components =%s" % (
+            self.name, str(self.components))
+
+    def to_json(self):
+        pass
+
 
 class BlueprintConfigModel(BaseModel):
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-client/python-client/src/main/python/ambari_client/model/host.py
----------------------------------------------------------------------
diff --git a/ambari-client/python-client/src/main/python/ambari_client/model/host.py b/ambari-client/python-client/src/main/python/ambari_client/model/host.py
index 05bdf6e..f6c39d6 100644
--- a/ambari-client/python-client/src/main/python/ambari_client/model/host.py
+++ b/ambari-client/python-client/src/main/python/ambari_client/model/host.py
@@ -219,8 +219,11 @@ def _bootstrap_hosts(root_resource, hosts_list, ssh_key, ssh_user):
     @param hosts_list list of host_names.
     @return: A  StatusModel object.
     """
-    payload_dic = {"verbose":True, "sshKey": ssh_key.encode(
-        'string_escape')  , "hosts":str(hosts_list) , "user": ssh_user }
+    payload_dic = {
+        "verbose": True,
+        "sshKey": ssh_key,
+        "hosts": str(hosts_list),
+        "user": ssh_user}
     resp = root_resource.post(
         paths.BOOTSTRAP_PATH,
         payload_dic,

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-client/python-client/src/main/python/ambari_client/model/paths.py
----------------------------------------------------------------------
diff --git a/ambari-client/python-client/src/main/python/ambari_client/model/paths.py b/ambari-client/python-client/src/main/python/ambari_client/model/paths.py
index 3643129..e111824 100644
--- a/ambari-client/python-client/src/main/python/ambari_client/model/paths.py
+++ b/ambari-client/python-client/src/main/python/ambari_client/model/paths.py
@@ -40,6 +40,7 @@ HOSTS_ASSIGN_ROLE = "/clusters/%s/hosts?Hosts/host_name=%s"
 BOOTSTRAP_PATH = "/bootstrap"
 REQUEST_STATUS_PATH = "/clusters/%s/requests/%s?fields=tasks/Tasks/status"
 REQUEST_PATH = "clusters/%s/requests/%s"
+REQUEST_N_PATH = "clusters/%s/requests?to=end&page_size=%s&fields=Requests"
 
 CONFIGURATION_PATH = "/clusters/%s/configurations?type=%s&tag=%s"
 CONFIGURATION_ALL_PATH = "/clusters/%s/configurations?type=%s"
@@ -57,3 +58,4 @@ TASKS_PATH = "clusters/%s/requests/%s/tasks?fields=*"
 
 BLUEPRINT_ALL_PATH = "blueprints?fields=*"
 BLUEPRINT_PATH = "blueprints/%s"
+BLUEPRINT_CLUSTER_PATH = "clusters/%s?format=blueprint"

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-client/python-client/src/main/python/ambari_client/model/status.py
----------------------------------------------------------------------
diff --git a/ambari-client/python-client/src/main/python/ambari_client/model/status.py b/ambari-client/python-client/src/main/python/ambari_client/model/status.py
index 37ca8fd..8ef1140 100644
--- a/ambari-client/python-client/src/main/python/ambari_client/model/status.py
+++ b/ambari-client/python-client/src/main/python/ambari_client/model/status.py
@@ -15,7 +15,7 @@
 #  limitations under the License.
 
 import logging
-from ambari_client.model.base_model import BaseModel
+from ambari_client.model.base_model import BaseModel, ModelList
 from ambari_client.model import paths, utils
 
 
@@ -32,7 +32,7 @@ class StatusModel(BaseModel):
     REF_ATTR = ('cluster_name',)
 
     def __init__(self, resource_root, status, requestId=None, message=None):
-        #BaseModel.__init__(self, **locals())
+        # BaseModel.__init__(self, **locals())
         utils.retain_self_helper(BaseModel, **locals())
 
     def __str__(self):
@@ -72,3 +72,41 @@ class StatusModel(BaseModel):
             return self.status
         else:
             None
+
+
+def _get_N_requests(resource_root, cluster_name, noOfrequest):
+    """
+    Get all services in a cluster.
+    @param cluster_name :Cluster name.
+    @return: A  ModelList object.
+    """
+    path = paths.REQUEST_N_PATH % (cluster_name, noOfrequest)
+    dic = resource_root.get(path)
+    return utils.ModelUtils.get_model_list(
+        ModelList,
+        RequestModel,
+        dic,
+        resource_root,
+        "Requests")
+
+
+class RequestModel(BaseModel):
+
+    """
+    The RequestModel class
+    """
+    RO_ATTR = ("request_context",)
+    RW_ATTR = ('id', 'request_status')
+    REF_ATTR = ('cluster_name',)
+
+    def __init__(self, resource_root, id, request_status=None):
+        # BaseModel.__init__(self, **locals())
+        utils.retain_self_helper(BaseModel, **locals())
+
+    def __str__(self):
+        return "<<RequestModel>> id = %s ; request_status = %s" % (
+            self.id, self.request_status)
+
+    def is_error(self):
+        return (
+            self.status != 200 and self.status != 201 and self.status != 202)

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-client/python-client/src/main/python/ambari_client/model/utils.py
----------------------------------------------------------------------
diff --git a/ambari-client/python-client/src/main/python/ambari_client/model/utils.py b/ambari-client/python-client/src/main/python/ambari_client/model/utils.py
index e1f1479..65dd153 100644
--- a/ambari-client/python-client/src/main/python/ambari_client/model/utils.py
+++ b/ambari-client/python-client/src/main/python/ambari_client/model/utils.py
@@ -162,12 +162,20 @@ class ModelUtils(object):
         rw_dict = {}
         LOG.debug("model_dict =   " + str(model_dict))
 
+        # extract model /keyword
         if isinstance(model_dict, dict) and RESOURCE_KEY_WORD in model_dict:
             model_dict = model_dict[RESOURCE_KEY_WORD]
-            LOG.debug(
-                "model_dict has %s ;subset = %s" %
-                (RESOURCE_KEY_WORD, str(
-                    model_dict.items())))
+            if not isinstance(model_dict, list):
+                LOG.debug(
+                    "model_dict has %s ;subset = %s" %
+                    (RESOURCE_KEY_WORD, str(
+                        model_dict.items())))
+            else:
+                LOG.debug(
+                    "model_dict is list and has %s ;subset = %s" %
+                    (RESOURCE_KEY_WORD, str(
+                        model_dict)))
+        # check for Requests
         if isinstance(model_dict, dict) and "Requests" in model_dict:
             model_dict = model_dict["Requests"]
             LOG.debug(
@@ -175,12 +183,17 @@ class ModelUtils(object):
                 (str(
                     model_dict.items())))
 
-        for k, v in model_dict.items():
-            LOG.debug("key = %s ; value = %s " % (str(k), str(v)))
-            if k in model_cls.RW_ATTR:
-                LOG.debug(k + " is there in RW_ATTR")
-                rw_dict[k] = v
-                del model_dict[k]
+        # check for composition i.e list of Models
+        if isinstance(model_dict, list):
+            LOG.debug(
+                "model_dict is list")
+        else:
+            for k, v in model_dict.items():
+                LOG.debug("key = %s ; value = %s " % (str(k), str(v)))
+                if k in model_cls.RW_ATTR:
+                    LOG.debug(k + " is there in RW_ATTR")
+                    rw_dict[k] = v
+                    del model_dict[k]
 
         rw_dict = get_unicode_kw(rw_dict)
         obj = model_cls(resource_root, **rw_dict)
@@ -238,7 +251,7 @@ def get_REF_object(ref_class_name):
 
 
 def get_unicode(v):
-    #import unicodedata
+    # import unicodedata
     if v:
         if isinstance(v, unicode):
             v = unicodedata.normalize('NFKD', v).encode('ascii', 'ignore')
@@ -249,8 +262,8 @@ def get_unicode(v):
 
 
 def retain_self_helper(memclass, self=None, **kwargs):
-        # print locals()
-        #from ambari_client.model.base_model import  BaseModel
+    # print locals()
+        # from ambari_client.model.base_model import  BaseModel
     memclass.__init__(self, **kwargs)
 
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/pom.xml
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/pom.xml b/ambari-shell/ambari-groovy-shell/pom.xml
new file mode 100644
index 0000000..a1acf8b
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/pom.xml
@@ -0,0 +1,142 @@
+<?xml version="1.0"?>
+<!-- Licensed under the Apache License, Version 2.0 (the "License"); you
+  may not use this file except in compliance with the License. You may obtain
+  a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless
+  required by applicable law or agreed to in writing, software distributed
+  under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
+  OR CONDITIONS OF ANY KIND, either express or implied. See the License for
+  the specific language governing permissions and limitations under the License.
+  See accompanying LICENSE file. -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <parent>
+    <groupId>org.apache.ambari</groupId>
+    <artifactId>ambari-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-groovy-shell</artifactId>
+  <packaging>jar</packaging>
+  <name>Ambari Groovy Shell</name>
+  <version>1.3.0-SNAPSHOT</version>
+  <description>Ambari Groovy Shell</description>
+   <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    <start-class>org.apache.ambari.shell.AmbariShell</start-class>
+  </properties>
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework.shell</groupId>
+      <artifactId>spring-shell</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework.boot</groupId>
+      <artifactId>spring-boot-starter-test</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.github.lalyos</groupId>
+      <artifactId>jfiglet</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>commons-io</groupId>
+      <artifactId>commons-io</artifactId>
+      <version>2.3</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.ambari</groupId>
+      <artifactId>groovy-client</artifactId>
+      <version>1.3.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-core</artifactId>
+      <version>1.9.5</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>jline</groupId>
+      <artifactId>jline</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.jackson</groupId>
+      <artifactId>jackson-mapper-asl</artifactId>
+    </dependency>
+  </dependencies>
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <version>3.0</version>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.rat</groupId>
+        <artifactId>apache-rat-plugin</artifactId>
+        <configuration>
+          <excludes>
+            <exclude>src/main/resources/elephant.txt</exclude>
+            <exclude>src/test/resources/2columns</exclude>
+            <exclude>src/test/resources/3columns</exclude>
+            <exclude>src/test/resources/testBlueprint.json</exclude>
+          </excludes>
+        </configuration>
+        <executions>
+          <execution>
+            <phase>test</phase>
+            <goals>
+              <goal>check</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <artifactId>maven-assembly-plugin</artifactId>
+        <configuration>
+          <skipAssembly>true</skipAssembly>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-maven-plugin</artifactId>
+        <version>1.0.2.RELEASE</version>
+        <executions>
+          <execution>
+            <goals>
+              <goal>repackage</goal>
+            </goals>
+          </execution>
+        </executions>
+        <configuration>
+          <mainClass>${start-class}</mainClass>
+        </configuration>
+      </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}/../../ambari-project/src/main/package/deb/control</controlDir>
+          <skip>true</skip>
+          <submodules>false</submodules>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/AmbariShell.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/AmbariShell.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/AmbariShell.java
new file mode 100644
index 0000000..e842620
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/AmbariShell.java
@@ -0,0 +1,111 @@
+/**
+ * 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;
+
+import org.apache.ambari.groovy.client.AmbariClient;
+import org.apache.ambari.shell.model.AmbariContext;
+import org.apache.ambari.shell.model.Hints;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.shell.CommandLine;
+import org.springframework.shell.core.JLineShellComponent;
+import org.springframework.shell.event.ShellStatus;
+import org.springframework.shell.event.ShellStatusListener;
+
+/**
+ * Shell bootstrap.
+ */
+@Configuration
+@ComponentScan(basePackageClasses = {AmbariShell.class})
+public class AmbariShell implements CommandLineRunner, ShellStatusListener {
+
+  @Autowired
+  private CommandLine commandLine;
+  @Autowired
+  private JLineShellComponent shell;
+  @Autowired
+  private AmbariContext context;
+  @Autowired
+  private AmbariClient client;
+
+  @Override
+  public void run(String... arg) throws Exception {
+    String[] shellCommandsToExecute = commandLine.getShellCommandsToExecute();
+    if (shellCommandsToExecute != null) {
+      for (String cmd : shellCommandsToExecute) {
+        if (!shell.executeScriptLine(cmd)) {
+          break;
+        }
+      }
+      System.exit(0);
+    } else {
+      shell.addShellStatusListener(this);
+      shell.start();
+      shell.promptLoop();
+      shell.waitForComplete();
+    }
+  }
+
+  @Override
+  public void onShellStatusChange(ShellStatus oldStatus, ShellStatus newStatus) {
+    if (newStatus.getStatus() == ShellStatus.Status.STARTED) {
+      try {
+        String cluster = client.getClusterName();
+        boolean available = client.isBlueprintAvailable();
+        if (cluster == null) {
+          if (available) {
+            context.setHint(Hints.BUILD_CLUSTER);
+          } else {
+            context.setHint(Hints.ADD_BLUEPRINT);
+          }
+        } else {
+          context.setHint(Hints.PROGRESS);
+        }
+        context.setCluster(cluster);
+        context.setBlueprintsAvailable(available);
+      } catch (Exception e) {
+        System.out.println(e.getMessage());
+        shell.executeCommand("quit");
+      }
+    }
+  }
+
+
+  public static void main(String[] args) {
+    if (args.length == 0) {
+      System.out.println(
+        "\nAmbari Shell: Interactive command line tool for managing Apache Ambari.\n\n" +
+          "Usage:\n" +
+          "  java -jar ambari-shell.jar                  : Starts Ambari Shell in interactive mode.\n" +
+          "  java -jar ambari-shell.jar --cmdfile=<FILE> : Ambari Shell executes commands read from the file.\n\n" +
+          "Options:\n" +
+          "  --ambari.host=<HOSTNAME>       Hostname of the Ambari Server [default: localhost].\n" +
+          "  --ambari.port=<PORT>           Port of the Ambari Server [default: 8080].\n" +
+          "  --ambari.user=<USER>           Username of the Ambari admin [default: admin].\n" +
+          "  --ambari.password=<PASSWORD>   Password of the Ambari admin [default: admin].\n\n" +
+          "Note:\n" +
+          "  At least one option is mandatory."
+      );
+      System.exit(1);
+    }
+    new SpringApplicationBuilder(AmbariShell.class).showBanner(false).run(args);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/BasicCommands.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/BasicCommands.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/BasicCommands.java
new file mode 100644
index 0000000..9babe12
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/BasicCommands.java
@@ -0,0 +1,207 @@
+/**
+ * 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.apache.ambari.shell.support.TableRenderer.renderMapValueMap;
+import static org.apache.ambari.shell.support.TableRenderer.renderSingleMap;
+
+import org.apache.ambari.groovy.client.AmbariClient;
+import org.apache.ambari.shell.model.AmbariContext;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.shell.core.CommandMarker;
+import org.springframework.shell.core.annotation.CliAvailabilityIndicator;
+import org.springframework.shell.core.annotation.CliCommand;
+import org.springframework.shell.core.annotation.CliOption;
+import org.springframework.stereotype.Component;
+
+/**
+ * Basic commands used in the shell. Delegating the commands
+ * to the Ambari Server via a Groovy based client.
+ *
+ * @see org.apache.ambari.groovy.client.AmbariClient
+ */
+@Component
+public class BasicCommands implements CommandMarker {
+
+  private AmbariClient client;
+  private AmbariContext context;
+
+  @Autowired
+  public BasicCommands(AmbariClient client, AmbariContext context) {
+    this.client = client;
+    this.context = context;
+  }
+
+  /**
+   * Checks whether the tasks command is available or not.
+   *
+   * @return true if its available false otherwise
+   */
+  @CliAvailabilityIndicator("tasks")
+  public boolean isTasksCommandAvailable() {
+    return context.isConnectedToCluster();
+  }
+
+  /**
+   * Prints the tasks of the Ambari Server.
+   *
+   * @param id id of the request
+   * @return task list
+   */
+  @CliCommand(value = "tasks", help = "Lists the Ambari tasks")
+  public String tasks(
+    @CliOption(key = "id", mandatory = false, help = "Id of the request; default is: 1", unspecifiedDefaultValue = "1") String id) {
+    return renderSingleMap(client.getTaskMap(id), "TASK", "STATUS");
+  }
+
+  /**
+   * Checks whether the service list command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator("services list")
+  public boolean isServiceListCommandAvailable() {
+    return context.isConnectedToCluster();
+  }
+
+  /**
+   * Prints the available service list of the Ambari Server.
+   *
+   * @return service list
+   */
+  @CliCommand(value = "services list", help = "Lists the available services")
+  public String servicesList() {
+    return renderSingleMap(client.getServicesMap(), "SERVICE", "STATE");
+  }
+
+  /**
+   * Checks whether the service components command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator("services components")
+  public boolean isServiceComponentsCommandAvailable() {
+    return context.isConnectedToCluster();
+  }
+
+  /**
+   * Prints the service components of the Ambari Server.
+   *
+   * @return service component list
+   */
+  @CliCommand(value = "services components", help = "Lists all services with their components")
+  public String serviceComponents() {
+    return renderMapValueMap(client.getServiceComponentsMap(), "SERVICE", "COMPONENT", "STATE");
+  }
+
+  /**
+   * Checks whether the debug on command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator("debug on")
+  public boolean isDebugOnCommandAvailable() {
+    return !client.isDebugEnabled();
+  }
+
+  /**
+   * Turns the debug on. From now on users will see the URLs of the API calls.
+   *
+   * @return status message
+   */
+  @CliCommand(value = "debug on", help = "Shows the URL of the API calls")
+  public String debugOn() {
+    client.setDebugEnabled(true);
+    return "debug enabled";
+  }
+
+  /**
+   * Checks whether the debug off command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator("debug off")
+  public boolean isDebugOffCommandAvailable() {
+    return client.isDebugEnabled();
+  }
+
+  /**
+   * Turns the debug off. URLs are not visible anymore.
+   *
+   * @return status message
+   */
+  @CliCommand(value = "debug off", help = "Stops showing the URL of the API calls")
+  public String debugOff() {
+    client.setDebugEnabled(false);
+    return "debug disabled";
+  }
+
+  /**
+   * Checks whether the hint command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator("hint")
+  public boolean isHintCommandAvailable() {
+    return true;
+  }
+
+  /**
+   * Provides some hints what you can do in the current context.
+   *
+   * @return hint message
+   */
+  @CliCommand(value = "hint", help = "Shows some hints")
+  public String hint() {
+    return context.getHint();
+  }
+
+  @CliAvailabilityIndicator("services stop")
+  public boolean isServiceStopCommandAvailable() {
+    return context.isConnectedToCluster();
+  }
+
+  @CliCommand(value = "services stop", help = "Stops all the running services")
+  public String stopServices() {
+    String message;
+    try {
+      client.stopAllServices();
+      message = "Stopping all services..";
+    } catch (Exception e) {
+      message = "Cannot stop services";
+    }
+    return String.format("%s\n\n%s", message, servicesList());
+  }
+
+  @CliAvailabilityIndicator("services start")
+  public boolean isServiceStartCommandAvailable() {
+    return context.isConnectedToCluster();
+  }
+
+  @CliCommand(value = "services start", help = "Starts all the services")
+  public String startServices() {
+    String message;
+    try {
+      client.startAllServices();
+      message = "Starting all services..";
+    } catch (Exception e) {
+      message = "Cannot start services";
+    }
+    return String.format("%s\n\n%s", message, servicesList());
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/BlueprintCommands.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/BlueprintCommands.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/BlueprintCommands.java
new file mode 100644
index 0000000..73000d0
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/BlueprintCommands.java
@@ -0,0 +1,198 @@
+/**
+ * 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.apache.ambari.shell.support.TableRenderer.renderMultiValueMap;
+import static org.apache.ambari.shell.support.TableRenderer.renderSingleMap;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.net.URL;
+
+import org.apache.ambari.groovy.client.AmbariClient;
+import org.apache.ambari.shell.completion.Blueprint;
+import org.apache.ambari.shell.model.AmbariContext;
+import org.apache.ambari.shell.model.Hints;
+import org.apache.commons.io.IOUtils;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.shell.core.CommandMarker;
+import org.springframework.shell.core.annotation.CliAvailabilityIndicator;
+import org.springframework.shell.core.annotation.CliCommand;
+import org.springframework.shell.core.annotation.CliOption;
+import org.springframework.stereotype.Component;
+
+/**
+ * Blueprint related commands used in the shell.
+ *
+ * @see org.apache.ambari.groovy.client.AmbariClient
+ */
+@Component
+public class BlueprintCommands implements CommandMarker {
+
+  private AmbariClient client;
+  private AmbariContext context;
+  private ObjectMapper jsonMapper;
+
+  @Autowired
+  public BlueprintCommands(AmbariClient client, AmbariContext context, ObjectMapper jsonMapper) {
+    this.client = client;
+    this.context = context;
+    this.jsonMapper = jsonMapper;
+  }
+
+  /**
+   * Checks whether the blueprints command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator("blueprint list")
+  public boolean isBlueprintListCommandAvailable() {
+    return context.areBlueprintsAvailable();
+  }
+
+  /**
+   * Prints all the blueprints.
+   *
+   * @return list of blueprints
+   */
+  @CliCommand(value = "blueprint list", help = "Lists all known blueprints")
+  public String listBlueprints() {
+    return renderSingleMap(client.getBlueprintsMap(), "BLUEPRINT", "STACK");
+  }
+
+  /**
+   * Checks whether the blueprint show command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator(value = "blueprint show")
+  public boolean isBlueprintShowCommandAvailable() {
+    return context.areBlueprintsAvailable();
+  }
+
+  /**
+   * Shows the requested blueprint's details.
+   *
+   * @param id id of the blueprint
+   * @return blueprint as formatted table
+   */
+  @CliCommand(value = "blueprint show", help = "Shows the blueprint by its id")
+  public String showBlueprint(
+    @CliOption(key = "id", mandatory = true, help = "Id of the blueprint") Blueprint id) {
+    return renderMultiValueMap(client.getBlueprintMap(id.getName()), "HOSTGROUP", "COMPONENT");
+  }
+
+  /**
+   * Checks whether the blueprint add command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator(value = "blueprint add")
+  public boolean isBlueprintAddCommandAvailable() {
+    return true;
+  }
+
+  /**
+   * Adds a blueprint to the Ambari server either through an URL or from a file.
+   * If both specified the file takes precedence.
+   *
+   * @param url  -optional, URL containing the blueprint json
+   * @param file - optional, file containing the blueprint json
+   * @return status message
+   */
+  @CliCommand(value = "blueprint add", help = "Add a new blueprint with either --url or --file")
+  public String addBlueprint(
+    @CliOption(key = "url", mandatory = false, help = "URL of the blueprint to download from") String url,
+    @CliOption(key = "file", mandatory = false, help = "File which contains the blueprint") File file) {
+    String message;
+    try {
+      String json = file == null ? readContent(url) : readContent(file);
+      if (json != null) {
+        client.addBlueprint(json);
+        context.setHint(Hints.BUILD_CLUSTER);
+        context.setBlueprintsAvailable(true);
+        message = String.format("Blueprint: '%s' has been added", getBlueprintName(json));
+      } else {
+        message = "No blueprint specified";
+      }
+    } catch (Exception e) {
+      message = "Cannot add blueprint: " + e.getMessage();
+    }
+    return message;
+  }
+
+  /**
+   * Checks whether the blueprint defaults command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator(value = "blueprint defaults")
+  public boolean isBlueprintDefaultsAddCommandAvailable() {
+    return !context.areBlueprintsAvailable();
+  }
+
+  /**
+   * Adds two default blueprints to the Ambari server.
+   *
+   * @return status message
+   */
+  @CliCommand(value = "blueprint defaults", help = "Adds the default blueprints to Ambari")
+  public String addBlueprint() {
+    String message = "Default blueprints added";
+    try {
+      client.addDefaultBlueprints();
+      context.setHint(Hints.BUILD_CLUSTER);
+      context.setBlueprintsAvailable(true);
+    } catch (Exception e) {
+      message = "Failed to add the default blueprints: " + e.getMessage();
+    }
+    return message;
+  }
+
+  private String readContent(File file) {
+    String content = null;
+    try {
+      content = IOUtils.toString(new FileInputStream(file));
+    } catch (IOException e) {
+      // not important
+    }
+    return content;
+  }
+
+  private String readContent(String url) {
+    String content = null;
+    try {
+      content = IOUtils.toString(new URL(url));
+    } catch (IOException e) {
+      // not important
+    }
+    return content;
+  }
+
+  private String getBlueprintName(String json) {
+    String result = "";
+    try {
+      result = jsonMapper.readTree(json.getBytes()).get("Blueprints").get("blueprint_name").asText();
+    } catch (IOException e) {
+      // not important
+    }
+    return result;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/ClusterCommands.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/ClusterCommands.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/ClusterCommands.java
new file mode 100644
index 0000000..dafdb85
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/ClusterCommands.java
@@ -0,0 +1,294 @@
+/**
+ * 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.apache.ambari.shell.support.TableRenderer.renderMultiValueMap;
+import static org.apache.ambari.shell.support.TableRenderer.renderSingleMap;
+
+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.FocusType;
+import org.apache.ambari.shell.model.Hints;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.shell.core.CommandMarker;
+import org.springframework.shell.core.annotation.CliAvailabilityIndicator;
+import org.springframework.shell.core.annotation.CliCommand;
+import org.springframework.shell.core.annotation.CliOption;
+import org.springframework.stereotype.Component;
+
+import groovyx.net.http.HttpResponseException;
+
+/**
+ * Cluster related commands used in the shell.
+ *
+ * @see org.apache.ambari.groovy.client.AmbariClient
+ */
+@Component
+public class ClusterCommands implements CommandMarker {
+
+  private AmbariClient client;
+  private AmbariContext context;
+  private FlashService flashService;
+  private Map<String, List<String>> hostGroups;
+
+  @Autowired
+  public ClusterCommands(AmbariClient client, AmbariContext context, FlashService flashService) {
+    this.client = client;
+    this.context = context;
+    this.flashService = flashService;
+  }
+
+  /**
+   * Checks whether the cluster build command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator("cluster build")
+  public boolean isClusterBuildCommandAvailable() {
+    return !context.isConnectedToCluster() && !context.isFocusOnClusterBuild() && context.areBlueprintsAvailable();
+  }
+
+  /**
+   * Sets the focus on cluster building. Takes a blueprint id, if it does not exists it wont focus.
+   * After focus the users are able to assign hosts to host groups.
+   *
+   * @param id id of the blueprint
+   * @return prints the blueprint as formatted table if exists, otherwise error message
+   */
+  @CliCommand(value = "cluster build", help = "Starts to build a cluster")
+  public String buildCluster(
+    @CliOption(key = "blueprint", mandatory = true, help = "Id of the blueprint, use 'blueprints' command to see the list") Blueprint id) {
+    String message;
+    String blueprint = id.getName();
+    if (client.doesBlueprintExist(blueprint)) {
+      context.setFocus(blueprint, FocusType.CLUSTER_BUILD);
+      context.setHint(Hints.ASSIGN_HOSTS);
+      message = String.format("%s\n%s",
+        renderSingleMap(client.getHostNames(), "HOSTNAME", "STATE"),
+        renderMultiValueMap(client.getBlueprintMap(blueprint), "HOSTGROUP", "COMPONENT"));
+      createNewHostGroups();
+    } else {
+      message = "Not a valid blueprint id";
+    }
+    return message;
+  }
+
+  /**
+   * Checks whether the cluster assign command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator("cluster assign")
+  public boolean isAssignCommandAvailable() {
+    return context.isFocusOnClusterBuild();
+  }
+
+  /**
+   * Assign hosts to host groups provided in the blueprint.
+   *
+   * @param host  host to assign
+   * @param group which host group to
+   * @return status message
+   */
+  @CliCommand(value = "cluster assign", help = "Assign host to host group")
+  public String assign(
+    @CliOption(key = "host", mandatory = true, help = "Fully qualified host name") Host host,
+    @CliOption(key = "hostGroup", mandatory = true, help = "Host group which to assign the host") String group) {
+    String message;
+    String hostName = host.getName();
+    if (client.getHostNames().keySet().contains(hostName)) {
+      if (addHostToGroup(hostName, group)) {
+        context.setHint(Hints.CREATE_CLUSTER);
+        message = String.format("%s has been added to %s", hostName, group);
+      } else {
+        message = String.format("%s is not a valid host group", group);
+      }
+    } else {
+      message = String.format("%s is not a valid hostname", hostName);
+    }
+    return message;
+  }
+
+  /**
+   * Checks whether the cluster auto command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator(value = "cluster autoAssign")
+  public boolean isClusterAutoAssignAvailable() {
+    return context.isFocusOnClusterBuild() && !isHostAssigned();
+  }
+
+  /**
+   * Tries to auto associate hosts to host groups.
+   *
+   * @return prints the auto assignments
+   */
+  @CliCommand(value = "cluster autoAssign", help = "Automatically assigns hosts to different host groups base on the provided strategy")
+  public String autoAssign() {
+    Map<String, List<String>> assignments = client.recommendAssignments(context.getFocusValue());
+    if (!assignments.isEmpty()) {
+      hostGroups = assignments;
+      context.setHint(Hints.CREATE_CLUSTER);
+    }
+    return showAssignments();
+  }
+
+  /**
+   * Checks whether the cluster preview command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator("cluster preview")
+  public boolean isClusterPreviewCommandAvailable() {
+    return context.isFocusOnClusterBuild() && isHostAssigned();
+  }
+
+  /**
+   * Shows the currently assigned hosts.
+   *
+   * @return formatted host - host group table
+   */
+  @CliCommand(value = "cluster preview", help = "Shows the currently assigned hosts")
+  public String showAssignments() {
+    return renderMultiValueMap(hostGroups, "HOSTGROUP", "HOST");
+  }
+
+  /**
+   * Checks whether the cluster create command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator("cluster create")
+  public boolean isCreateClusterCommandAvailable() {
+    return context.isFocusOnClusterBuild() && isHostAssigned();
+  }
+
+  /**
+   * Creates a new cluster based on the provided host - host group associations and the selected blueprint.
+   * If the cluster creation fails, deletes the cluster.
+   *
+   * @return status message
+   */
+  @CliCommand(value = "cluster create", help = "Create a cluster based on current blueprint and assigned hosts")
+  public String createCluster(
+    @CliOption(key = "exitOnFinish", mandatory = false, help = "Quits the shell when the cluster creation finishes") Boolean exit) {
+    String message = "Successfully created the cluster";
+    String blueprint = context.getFocusValue();
+    try {
+      client.createCluster(blueprint, blueprint, hostGroups);
+      context.setCluster(blueprint);
+      context.resetFocus();
+      context.setHint(Hints.PROGRESS);
+      flashService.showInstallProgress(exit == null ? false : exit);
+    } catch (HttpResponseException e) {
+      createNewHostGroups();
+      message = "Failed to create the cluster: " + e.getMessage();
+      try {
+        deleteCluster(blueprint);
+      } catch (HttpResponseException e1) {
+        message += ". Failed to cleanup cluster creation: " + e1.getMessage();
+      }
+    }
+    return message;
+  }
+
+  /**
+   * Checks whether the cluster delete command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator("cluster delete")
+  public boolean isDeleteClusterCommandAvailable() {
+    return context.isConnectedToCluster();
+  }
+
+  /**
+   * Deletes the cluster.
+   *
+   * @return status message
+   */
+  @CliCommand(value = "cluster delete", help = "Delete the cluster")
+  public String deleteCluster() {
+    String message = "Successfully deleted the cluster";
+    try {
+      deleteCluster(context.getCluster());
+    } catch (HttpResponseException e) {
+      message = "Could not delete the cluster: " + e.getMessage();
+    }
+    return message;
+  }
+
+  /**
+   * Checks whether the cluster reset command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator(value = "cluster reset")
+  public boolean isClusterResetCommandAvailable() {
+    return context.isFocusOnClusterBuild() && isHostAssigned();
+  }
+
+  @CliCommand(value = "cluster reset", help = "Clears the host - host group assignments")
+  public void reset() {
+    context.setHint(Hints.ASSIGN_HOSTS);
+    createNewHostGroups();
+  }
+
+  private void deleteCluster(String id) throws HttpResponseException {
+    client.deleteCluster(id);
+  }
+
+  private void createNewHostGroups() {
+    Map<String, List<String>> groups = new HashMap<String, List<String>>();
+    for (String hostGroup : client.getHostGroups(context.getFocusValue())) {
+      groups.put(hostGroup, new ArrayList<String>());
+    }
+    this.hostGroups = groups;
+  }
+
+  private boolean addHostToGroup(String host, String group) {
+    boolean result = true;
+    List<String> hosts = hostGroups.get(group);
+    if (hosts == null) {
+      result = false;
+    } else {
+      hosts.add(host);
+    }
+    return result;
+  }
+
+  private boolean isHostAssigned() {
+    boolean result = false;
+    for (String group : hostGroups.keySet()) {
+      if (!hostGroups.get(group).isEmpty()) {
+        result = true;
+        break;
+      }
+    }
+    return result;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/ElephantCommand.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/ElephantCommand.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/ElephantCommand.java
new file mode 100644
index 0000000..a236054
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/ElephantCommand.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.commands;
+
+import java.io.IOException;
+
+import org.apache.commons.io.IOUtils;
+import org.springframework.shell.core.CommandMarker;
+import org.springframework.shell.core.annotation.CliAvailabilityIndicator;
+import org.springframework.shell.core.annotation.CliCommand;
+import org.springframework.stereotype.Component;
+
+/**
+ * Draws an elephant to the console.
+ */
+@Component
+public class ElephantCommand implements CommandMarker {
+
+  /**
+   * Checks whether the hello command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator("hello")
+  public boolean isCommandAvailable() {
+    return true;
+  }
+
+  /**
+   * Prints an elephant to the console.
+   *
+   * @return elephant
+   */
+  @CliCommand(value = "hello", help = "Prints a simple elephant to the console")
+  public String elephant() throws IOException {
+    return IOUtils.toString(getClass().getResourceAsStream("/elephant.txt"));
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/HostCommands.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/HostCommands.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/HostCommands.java
new file mode 100644
index 0000000..dd3c775
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/commands/HostCommands.java
@@ -0,0 +1,119 @@
+/**
+ * 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.apache.ambari.shell.support.TableRenderer.renderSingleMap;
+
+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.springframework.beans.factory.annotation.Autowired;
+import org.springframework.shell.core.CommandMarker;
+import org.springframework.shell.core.annotation.CliAvailabilityIndicator;
+import org.springframework.shell.core.annotation.CliCommand;
+import org.springframework.shell.core.annotation.CliOption;
+import org.springframework.stereotype.Component;
+
+/**
+ * Host related commands used in the shell.
+ *
+ * @see org.apache.ambari.groovy.client.AmbariClient
+ */
+@Component
+public class HostCommands implements CommandMarker {
+
+  private AmbariClient client;
+  private AmbariContext context;
+
+  @Autowired
+  public HostCommands(AmbariClient client, AmbariContext context) {
+    this.client = client;
+    this.context = context;
+  }
+
+  /**
+   * Checks whether the host list command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator("host list")
+  public boolean isHostsCommandAvailable() {
+    return true;
+  }
+
+  /**
+   * Prints the available hosts of the Ambari Server.
+   *
+   * @return host list
+   */
+  @CliCommand(value = "host list", help = "Lists the available hosts")
+  public String hosts() {
+    return client.showHostList();
+  }
+
+  /**
+   * Checks whether the host focus command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator("host focus")
+  public boolean isFocusHostCommandAvailable() {
+    return context.isConnectedToCluster();
+  }
+
+  /**
+   * Sets the focus to the specified host.
+   *
+   * @param host the host to set the focus to
+   * @return status message
+   */
+  @CliCommand(value = "host focus", help = "Sets the useHost to the specified host")
+  public String focusHost(
+    @CliOption(key = "host", mandatory = true, help = "hostname") Host host) {
+    String message;
+    String hostName = host.getName();
+    if (client.getHostNames().keySet().contains(hostName)) {
+      context.setFocus(hostName, FocusType.HOST);
+      message = "Focus set to: " + hostName;
+    } else {
+      message = hostName + " is not a valid host name";
+    }
+    return message;
+  }
+
+  /**
+   * Checks whether the host components command is available or not.
+   *
+   * @return true if available false otherwise
+   */
+  @CliAvailabilityIndicator("host components")
+  public boolean isHostComponentsCommandAvailable() {
+    return context.isFocusOnHost();
+  }
+
+  /**
+   * Prints the components which belongs to the host being focused on.
+   *
+   * @return list of host components
+   */
+  @CliCommand(value = "host components", help = "Lists the components assigned to the selected host")
+  public String hostComponents() {
+    return renderSingleMap(client.getHostComponentsMap(context.getFocusValue()), "COMPONENT", "STATE");
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/completion/Blueprint.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/completion/Blueprint.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/completion/Blueprint.java
new file mode 100644
index 0000000..4eec7b1
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/completion/Blueprint.java
@@ -0,0 +1,34 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.shell.completion;
+
+/**
+ * Wrapper class for TAB completion to blueprint names.
+ */
+public class Blueprint {
+
+  private final String name;
+
+  public Blueprint(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/completion/Host.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/completion/Host.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/completion/Host.java
new file mode 100644
index 0000000..f64e97b
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/completion/Host.java
@@ -0,0 +1,34 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.ambari.shell.completion;
+
+/**
+ * Wrapper class for TAB completion to host names.
+ */
+public class Host {
+
+  private final String name;
+
+  public Host(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/configuration/ConverterConfiguration.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/configuration/ConverterConfiguration.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/configuration/ConverterConfiguration.java
new file mode 100644
index 0000000..049c52f
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/configuration/ConverterConfiguration.java
@@ -0,0 +1,142 @@
+/**
+ * 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.configuration;
+
+import org.apache.ambari.groovy.client.AmbariClient;
+import org.apache.ambari.shell.converter.BlueprintConverter;
+import org.apache.ambari.shell.converter.HostConverter;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.shell.converters.AvailableCommandsConverter;
+import org.springframework.shell.converters.BigDecimalConverter;
+import org.springframework.shell.converters.BigIntegerConverter;
+import org.springframework.shell.converters.BooleanConverter;
+import org.springframework.shell.converters.CharacterConverter;
+import org.springframework.shell.converters.DateConverter;
+import org.springframework.shell.converters.DoubleConverter;
+import org.springframework.shell.converters.EnumConverter;
+import org.springframework.shell.converters.FloatConverter;
+import org.springframework.shell.converters.IntegerConverter;
+import org.springframework.shell.converters.LocaleConverter;
+import org.springframework.shell.converters.LongConverter;
+import org.springframework.shell.converters.ShortConverter;
+import org.springframework.shell.converters.SimpleFileConverter;
+import org.springframework.shell.converters.StaticFieldConverterImpl;
+import org.springframework.shell.converters.StringConverter;
+import org.springframework.shell.core.Converter;
+
+/**
+ * Configures the converters used by the shell.
+ */
+@Configuration
+public class ConverterConfiguration {
+
+  @Autowired
+  private AmbariClient client;
+
+  @Bean
+  Converter simpleFileConverter() {
+    return new SimpleFileConverter();
+  }
+
+  @Bean
+  Converter stringConverter() {
+    return new StringConverter();
+  }
+
+  @Bean
+  Converter availableCommandsConverter() {
+    return new AvailableCommandsConverter();
+  }
+
+  @Bean
+  Converter bigDecimalConverter() {
+    return new BigDecimalConverter();
+  }
+
+  @Bean
+  Converter bigIntegerConverter() {
+    return new BigIntegerConverter();
+  }
+
+  @Bean
+  Converter booleanConverter() {
+    return new BooleanConverter();
+  }
+
+  @Bean
+  Converter characterConverter() {
+    return new CharacterConverter();
+  }
+
+  @Bean
+  Converter dateConverter() {
+    return new DateConverter();
+  }
+
+  @Bean
+  Converter doubleConverter() {
+    return new DoubleConverter();
+  }
+
+  @Bean
+  Converter enumConverter() {
+    return new EnumConverter();
+  }
+
+  @Bean
+  Converter floatConverter() {
+    return new FloatConverter();
+  }
+
+  @Bean
+  Converter integerConverter() {
+    return new IntegerConverter();
+  }
+
+  @Bean
+  Converter localeConverter() {
+    return new LocaleConverter();
+  }
+
+  @Bean
+  Converter longConverter() {
+    return new LongConverter();
+  }
+
+  @Bean
+  Converter shortConverter() {
+    return new ShortConverter();
+  }
+
+  @Bean
+  Converter staticFieldConverterImpl() {
+    return new StaticFieldConverterImpl();
+  }
+
+  @Bean
+  Converter blueprintConverter() {
+    return new BlueprintConverter(client);
+  }
+
+  @Bean
+  Converter hostConverter() {
+    return new HostConverter(client);
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/configuration/ShellConfiguration.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/configuration/ShellConfiguration.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/configuration/ShellConfiguration.java
new file mode 100644
index 0000000..4c493b0
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/configuration/ShellConfiguration.java
@@ -0,0 +1,114 @@
+/**
+ * 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.configuration;
+
+import org.apache.ambari.groovy.client.AmbariClient;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
+import org.springframework.scheduling.concurrent.ThreadPoolExecutorFactoryBean;
+import org.springframework.shell.CommandLine;
+import org.springframework.shell.SimpleShellCommandLineOptions;
+import org.springframework.shell.commands.ExitCommands;
+import org.springframework.shell.commands.HelpCommands;
+import org.springframework.shell.commands.ScriptCommands;
+import org.springframework.shell.commands.VersionCommands;
+import org.springframework.shell.core.CommandMarker;
+import org.springframework.shell.core.JLineShellComponent;
+import org.springframework.shell.plugin.HistoryFileNameProvider;
+import org.springframework.shell.plugin.support.DefaultHistoryFileNameProvider;
+
+/**
+ * Spring bean definitions.
+ */
+@Configuration
+public class ShellConfiguration {
+
+  @Value("${ambari.host:localhost}")
+  private String host;
+
+  @Value("${ambari.port:8080}")
+  private String port;
+
+  @Value("${ambari.user:admin}")
+  private String user;
+
+  @Value("${ambari.password:admin}")
+  private String password;
+
+  @Value("${cmdfile:}")
+  private String cmdFile;
+
+  @Bean
+  AmbariClient createAmbariClient() {
+    return new AmbariClient(host, port, user, password);
+  }
+
+  @Bean
+  static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
+    return new PropertySourcesPlaceholderConfigurer();
+  }
+
+  @Bean
+  HistoryFileNameProvider defaultHistoryFileNameProvider() {
+    return new DefaultHistoryFileNameProvider();
+  }
+
+  @Bean(name = "shell")
+  JLineShellComponent shell() {
+    return new JLineShellComponent();
+  }
+
+  @Bean
+  CommandLine commandLine() throws Exception {
+    String[] args = cmdFile.length() > 0 ? new String[]{"--cmdfile", cmdFile} : new String[0];
+    return SimpleShellCommandLineOptions.parseCommandLine(args);
+  }
+
+  @Bean
+  ThreadPoolExecutorFactoryBean getThreadPoolExecutorFactoryBean() {
+    return new ThreadPoolExecutorFactoryBean();
+  }
+
+  @Bean
+  ObjectMapper getObjectMapper() {
+    return new ObjectMapper();
+  }
+
+  @Bean
+  CommandMarker exitCommand() {
+    return new ExitCommands();
+  }
+
+  @Bean
+  CommandMarker versionCommands() {
+    return new VersionCommands();
+  }
+
+  @Bean
+  CommandMarker helpCommands() {
+    return new HelpCommands();
+  }
+
+  @Bean
+  CommandMarker scriptCommands() {
+    return new ScriptCommands();
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/converter/BlueprintConverter.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/converter/BlueprintConverter.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/converter/BlueprintConverter.java
new file mode 100644
index 0000000..7984e7f
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/converter/BlueprintConverter.java
@@ -0,0 +1,58 @@
+/**
+ * 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.converter;
+
+import java.util.List;
+import java.util.Set;
+
+import org.apache.ambari.groovy.client.AmbariClient;
+import org.apache.ambari.shell.completion.Blueprint;
+import org.springframework.shell.core.Completion;
+import org.springframework.shell.core.Converter;
+import org.springframework.shell.core.MethodTarget;
+
+/**
+ * Converter used to complete blueprint names.
+ */
+public class BlueprintConverter implements Converter<Blueprint> {
+
+  private AmbariClient client;
+
+  public BlueprintConverter(AmbariClient client) {
+    this.client = client;
+  }
+
+  @Override
+  public boolean supports(Class<?> type, String optionContext) {
+    return Blueprint.class.isAssignableFrom(type);
+  }
+
+  @Override
+  public Blueprint convertFromText(String value, Class<?> targetType, String optionContext) {
+    return new Blueprint(value);
+  }
+
+  @Override
+  public boolean getAllPossibleValues(List<Completion> completions, Class<?> targetType, String existingData, String optionContext, MethodTarget target) {
+    Set<String> blueprints = client.getBlueprintsMap().keySet();
+    for (String blueprint : blueprints) {
+      completions.add(new Completion(blueprint));
+    }
+    return true;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/converter/HostConverter.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/converter/HostConverter.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/converter/HostConverter.java
new file mode 100644
index 0000000..39aa6e9
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/converter/HostConverter.java
@@ -0,0 +1,58 @@
+/**
+ * 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.converter;
+
+import java.util.List;
+import java.util.Set;
+
+import org.apache.ambari.groovy.client.AmbariClient;
+import org.apache.ambari.shell.completion.Host;
+import org.springframework.shell.core.Completion;
+import org.springframework.shell.core.Converter;
+import org.springframework.shell.core.MethodTarget;
+
+/**
+ * Converter used to complete host names.
+ */
+public class HostConverter implements Converter<Host> {
+
+  private AmbariClient client;
+
+  public HostConverter(AmbariClient client) {
+    this.client = client;
+  }
+
+  @Override
+  public boolean supports(Class<?> type, String optionContext) {
+    return Host.class.isAssignableFrom(type);
+  }
+
+  @Override
+  public Host convertFromText(String value, Class<?> targetType, String optionContext) {
+    return new Host(value);
+  }
+
+  @Override
+  public boolean getAllPossibleValues(List<Completion> completions, Class<?> targetType, String existingData, String optionContext, MethodTarget target) {
+    Set<String> hosts = client.getHostNames().keySet();
+    for (String host : hosts) {
+      completions.add(new Completion(host));
+    }
+    return true;
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/customization/AmbariBanner.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/customization/AmbariBanner.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/customization/AmbariBanner.java
new file mode 100644
index 0000000..f97ef59
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/customization/AmbariBanner.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.shell.customization;
+
+import org.springframework.shell.plugin.BannerProvider;
+import org.springframework.stereotype.Component;
+
+import com.github.lalyos.jfiglet.FigletFont;
+
+/**
+ * Prints the banner when the user starts the shell.
+ */
+@Component
+public class AmbariBanner implements BannerProvider {
+
+  @Override
+  public String getProviderName() {
+    return "AmbariShell";
+  }
+
+  @Override
+  public String getBanner() {
+    return FigletFont.convertOneLine("AmbariShell");
+  }
+
+  @Override
+  public String getVersion() {
+    return getClass().getPackage().getImplementationVersion();
+  }
+
+  @Override
+  public String getWelcomeMessage() {
+    return "Welcome to Ambari Shell. For command and param completion press TAB, for assistance type 'hint'.";
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/customization/AmbariHistory.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/customization/AmbariHistory.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/customization/AmbariHistory.java
new file mode 100644
index 0000000..c23fc9a
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/customization/AmbariHistory.java
@@ -0,0 +1,40 @@
+/**
+ * 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 org.springframework.shell.plugin.HistoryFileNameProvider;
+import org.springframework.stereotype.Component;
+
+/**
+ * Specifies the name of the Ambari command log. Later this log can be used
+ * to re-execute the commands with either the --cmdfile option at startup
+ * or with the script --file command.
+ */
+@Component
+public class AmbariHistory implements HistoryFileNameProvider {
+
+  @Override
+  public String getHistoryFileName() {
+    return "ambari-log.ash";
+  }
+
+  @Override
+  public String getProviderName() {
+    return "AmbariShell";
+  }
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/customization/AmbariPrompt.java
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/customization/AmbariPrompt.java b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/customization/AmbariPrompt.java
new file mode 100644
index 0000000..b91e76e
--- /dev/null
+++ b/ambari-shell/ambari-groovy-shell/src/main/java/org/apache/ambari/shell/customization/AmbariPrompt.java
@@ -0,0 +1,43 @@
+/**
+ * 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 org.apache.ambari.shell.model.AmbariContext;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.shell.plugin.PromptProvider;
+import org.springframework.stereotype.Component;
+
+/**
+ * Manages the text of the shell's prompt.
+ */
+@Component
+public class AmbariPrompt implements PromptProvider {
+
+  @Autowired
+  private AmbariContext context;
+
+  @Override
+  public String getProviderName() {
+    return AmbariPrompt.class.getSimpleName();
+  }
+
+  @Override
+  public String getPrompt() {
+    return context.getPrompt();
+  }
+}


[2/4] AMBARI-6176. Integrate python shell into Ambari-shell module(subin)

Posted by su...@apache.org.
http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/ambari_shell.py
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/ambari_shell.py b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/ambari_shell.py
new file mode 100644
index 0000000..79af1a6
--- /dev/null
+++ b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/ambari_shell.py
@@ -0,0 +1,412 @@
+#!/usr/bin/env python
+#
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+
+import logging
+import logging.handlers
+import sys
+import signal
+import json
+import time
+import pdb
+import os
+import stat
+import cmd
+import string
+import bz2
+import datetime
+# import traceback
+import getpass
+import argparse
+import readline
+import ConfigParser
+import StringIO
+import subprocess
+import textwrap
+
+import utils.displayutils
+import utils.osutils
+import utils.pluginutils
+from ambari_client.ambari_api import AmbariClient
+
+
+configFile = "/etc/ambari-shell/conf/ambari-shell.ini"
+
+
+formatstr = "%(levelname)s %(asctime)s %(filename)s:%(lineno)d - %(message)s"
+LOG_MAX_BYTES = 10000000
+LOG_BACKUP = 2
+
+SHELL_CONFIG = {
+    'clustername': None,
+    'hostname': 'localhost',
+    'port': 8080,
+    'username': 'admin',
+    'password': 'admin',
+    'display_type': 'table',
+    'client': None,
+    'configFile': configFile}
+
+########################################################################
+#
+# Utility methods
+#
+########################################################################
+
+
+def exit_gracefully(signum, frame):
+    # restore the original signal handler as otherwise evil things will happen
+    # in raw_input when CTRL+C is pressed, and our signal handler is not
+    # re-entrant
+    signal.signal(signal.SIGINT, original_sigint)
+    print "\nExiting"
+    sys.exit(1)
+
+    # restore the exit gracefully handler here
+    signal.signal(signal.SIGINT, exit_gracefully)
+
+
+def exit_gracefully1(signum, frame):
+    # restore the original signal handler as otherwise evil things will happen
+    # in raw_input when CTRL+C is pressed, and our signal handler is not
+    # re-entrant
+    signal.signal(signal.SIGQUIT, original_sigint)
+    print "\nExiting"
+    sys.exit(1)
+
+    # restore the exit gracefully handler here
+    signal.signal(signal.SIGQUIT, exit_gracefully)
+
+
+def resolve_config():
+    try:
+        config = ConfigParser.RawConfigParser()
+        if os.path.exists(configFile):
+            print "looking  from " + configFile
+            config.read(configFile)
+        else:
+            raise Exception("No config found")
+    except Exception as err:
+        logging.warn(err)
+    print "found " + configFile
+    return config
+
+
+def get_log_level(loglevel):
+    loglev = loglevel.upper()
+    if loglev == "DEBUG":
+        return logging.DEBUG
+    elif loglev == "INFO":
+        return logging.INFO
+    elif loglev == "WARNING":
+        return logging.WARNING
+    elif loglev == "CRITICAL":
+        return logging.CRITICAL
+    elif loglev == "ERROR":
+        return logging.ERROR
+    elif loglev == "FATAL":
+        return logging.FATAL
+    else:
+        return logging.NOTSET
+
+
+def setup_logging(loglevel, logPath="./"):
+    try:
+        logging.root
+        curTimestamp = str(datetime.datetime.now())
+        ct = curTimestamp.split('.')[0]
+        curTime = ct.replace(':', '-')
+        datee = curTime.split(' ')[0]
+        timee = curTime.split(' ')[1]
+        # Set Log directory and log file name. Each run generates a new log
+        # file
+
+        logFile = logPath + 'ambaricli_' + datee + "_" + timee + '.log'
+        fh = open(logFile, 'w')
+        fh.write('*****************************************************\n')
+        fh.write('                Amabri Python CLI Log\n')
+        t = '                Timestamp: ' + ct + '\n'
+        fh.write(t)
+        fh.write('*****************************************************\n\n\n')
+        fh.close()
+        # Set the config for logging
+        logging.basicConfig(
+            filename=logFile,
+            format='%(asctime)s : %(levelname)s: %(message)s',
+            level=get_log_level(loglevel))
+    except IOError as e:
+        errStr = "  I/O error({0}): {1}".format(e.errno, e.strerror)
+        print errStr
+        sys.exit(1)
+    except Exception as exception:
+        print exception
+        sys.exit(1)
+
+
+def getLogLevel(configg):
+    loglevel = "debug"
+    try:
+        loglevel = configg.get('python_shell', 'loglevel')
+    except Exception:
+        logging.error("No loglevel found ")
+        return loglevel
+    return loglevel
+
+
+def getLogPath(configg):
+    logPath = "./"
+    try:
+        logPath = configg.get('python_shell', 'log_folder')
+    except Exception:
+        logging.error("No log_folder found")
+        return logPath
+    return logPath
+
+
+def getPluginPath(configg):
+    cliplugin_path = "./"
+    try:
+        cliplugin_path = configg.get('python_shell', 'cliplugin_folder')
+    except Exception:
+        logging.error("No cliplugin_folder found")
+        return cliplugin_path
+    return cliplugin_path
+
+
+def getDefaultPluginPath(configg):
+    cliplugin_path = "./"
+    try:
+        cliplugin_path = configg.get('python_shell', 'default_plugin_folder')
+    except Exception:
+        logging.error("No default_plugin_folder found")
+        return cliplugin_path
+    return cliplugin_path
+
+
+def getCommandsDict(ppath, cliplugin_path):
+    default_dictt = utils.pluginutils.getPlugins(ppath)
+    logging.debug("pluginutils returned default plugins >> %s ", default_dictt)
+    dictt = utils.pluginutils.getPlugins(cliplugin_path)
+    logging.debug("pluginutils returned >> %s ", dictt)
+    if(not set(default_dictt).isdisjoint(set(dictt))):
+        common_commands = set(default_dictt).intersection(set(dictt))
+        common_commands = " & ".join(str(x) for x in common_commands)
+        logging.error(
+            "ERROR :plugins folder has duplicate commands already present in default commands")
+        logging.error(common_commands)
+        print "ERROR :plugins folder has duplicate command already present in default commands"
+        print "pls remove following commands from plugin folder >" + str(common_commands)
+        sys.exit(1)
+    default_dictt.update(dictt)
+    return default_dictt
+
+
+class CmdBase(cmd.Cmd):
+
+    """CLI .
+    """
+
+    intro = utils.displayutils.shellBanner()
+    prompt = 'ambari>'
+    http_proxy = ''
+    https_proxy = ''
+    # headers
+    doc_header = "Commands"
+    undoc_header = "Other Commands"
+
+    def __init__(self):
+        cmd.Cmd.__init__(self)
+
+    def do_EOF(self, line):
+        logging.info("====== do_EOF ======")
+        return True
+
+    def do_exit(self, line):
+        logging.info("====== do_exit ======")
+        return True
+
+    def postloop(self):
+        logging.info("====== exit ======")
+
+#    def parseline(self, line):
+#        print 'parseline(%s) =>' % line,
+#        ret = cmd.Cmd.parseline(self, line)
+#        print ret
+#        return ret
+
+    def emptyline(self):
+        # print 'emptyline()'
+        # return cmd.Cmd.emptyline(self)
+        return
+
+    def default(self, line):
+        """Called on an input line when the command prefix is not recognized.
+
+        If this method is not overridden, it prints an error message and
+        returns.
+
+        """
+        self.stdout.write(
+            '*** Unknown command *** : %s \n type "help" to list all commands \n' %
+            line)
+
+
+class AmbariShell(CmdBase):
+
+    COMPONENTS = {}
+    SERVICES = None
+    CLUSTERS = None
+
+    def __init__(self):
+        CmdBase.__init__(self)
+        self.config = None
+        self.global_shell_config = SHELL_CONFIG
+
+    def preloop(self):
+        "Checks if the cluster was pre-defined"
+        self._set_prompt()
+
+    def _set_prompt(self):
+        if self.global_shell_config['clustername']:
+            self.prompt = "ambari-" + \
+                str(self.global_shell_config['clustername']) + ">"
+            logging.debug("found a cluster >" +
+                          str(self.global_shell_config['clustername']))
+        else:
+            self.prompt = 'ambari>'
+
+    def postcmd(self, stop, line):
+        # print 'postcmd(%s, %s)' % (stop, line)
+        self._set_prompt()
+        return cmd.Cmd.postcmd(self, stop, line)
+
+    def setConfig(self, customConfig):
+        self.config = customConfig
+
+    # core code should begin here
+
+    def generate_output(self, headers, rows):
+        if self.global_shell_config['display_type'] == "table":
+            print utils.displayutils.display_table(headers, rows)
+
+        if self.global_shell_config['display_type'] == "csv":
+            utils.displayutils.createCSV(headers, rows)
+
+        if self.global_shell_config['display_type'] == "xml":
+            print utils.displayutils.createXML(headers, rows)
+
+#
+# The "main" function
+
+
+def main():
+    parser = argparse.ArgumentParser(description='Ambari CLI')
+    parser.add_argument('-H', '--host', action='store', dest='host')
+    parser.add_argument(
+        '-p',
+        '--port',
+        action='store',
+        dest='port',
+        type=int,
+        default=8080)
+    parser.add_argument(
+        '-u',
+        '--user',
+        action='store',
+        dest='user',
+        default='admin')
+    parser.add_argument(
+        '-c',
+        '--clustername',
+        action='store',
+        dest='clustername')
+    parser.add_argument(
+        '--password',
+        action='store',
+        dest='password',
+        default='admin')
+    parser.add_argument(
+        '-d',
+        '--display_type',
+        action='store',
+        dest='display_type',
+        default='table')
+    parser.add_argument('-r', '--run', action='store', dest='run')
+    args = parser.parse_args()
+
+    # Check if a username was suplied, if not, prompt the user
+    if not args.host:
+        args.host = raw_input("Enter Ambari Server host: ")
+
+    if args.host:
+        SHELL_CONFIG['hostname'] = args.host
+    if args.clustername:
+        SHELL_CONFIG['clustername'] = args.clustername
+    if args.display_type:
+        SHELL_CONFIG['display_type'] = args.display_type
+
+    headers_dict = {'X-Requested-By': 'mycompany'}
+    client = AmbariClient(
+        SHELL_CONFIG['hostname'],
+        SHELL_CONFIG['port'],
+        SHELL_CONFIG['username'],
+        SHELL_CONFIG['password'],
+        version=1,
+        http_header=headers_dict)
+    SHELL_CONFIG['client'] = client
+
+    # do some plumbing
+    config = resolve_config()
+    logPath = getLogPath(config)
+    loglevel = getLogLevel(config)
+    cliplugin_path = getPluginPath(config)
+    dpath = getDefaultPluginPath(config)
+    setup_logging(loglevel, logPath)
+    # get ready to create a shell
+    utils.osutils.doclearScreen()
+    shell = AmbariShell()
+    logging.info("cliplugin_folder =  %s", getPluginPath(config))
+    logging.info("SHELL_CONFIG =  %s", str(SHELL_CONFIG))
+    # Get all commands
+
+    commands_dictt = getCommandsDict(dpath, cliplugin_path)
+    for k, v in commands_dictt.items():
+        setattr(AmbariShell, str(k), v)
+    shell.setConfig(config)
+
+    # Check if user is attempting non-interactive shell
+    if args.run:
+        print args.run
+        for command in args.run.split(';'):
+            shell.onecmd(command)
+            sys.exit(0)
+    else:
+        try:
+            shell.cmdloop()
+        except KeyboardInterrupt:
+            sys.stdout.write("\n")
+            sys.exit(0)
+    logging.info("finished")
+
+
+if __name__ == '__main__':
+    original_sigint = signal.getsignal(signal.SIGINT)
+    signal.signal(signal.SIGINT, exit_gracefully)
+    signal.signal(signal.SIGQUIT, exit_gracefully1)
+    signal.signal(signal.SIGTERM, exit_gracefully1)
+    main()

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/__init__.py
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/__init__.py b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/__init__.py
new file mode 100644
index 0000000..278df2e
--- /dev/null
+++ b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/__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.

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/blueprint.py
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/blueprint.py b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/blueprint.py
new file mode 100644
index 0000000..4d65163
--- /dev/null
+++ b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/blueprint.py
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+#
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+import logging
+import textwrap
+
+LOG = logging.getLogger(__name__)

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/connect_cluster.py
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/connect_cluster.py b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/connect_cluster.py
new file mode 100644
index 0000000..c28d493
--- /dev/null
+++ b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/connect_cluster.py
@@ -0,0 +1,81 @@
+#!/usr/bin/env python
+#
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+import logging
+import textwrap
+
+LOG = logging.getLogger(__name__)
+
+
+def do_connect_cluster(self, cluster):
+
+    if not cluster:
+        self.help_connect_cluster()
+        return None
+
+    if not self.CLUSTERS:
+        clusters = [str(c.cluster_name).encode('ascii', 'ignore')
+                    for c in self.global_shell_config['client'].get_all_clusters()]
+        self.CLUSTERS = clusters
+
+    if cluster not in self.CLUSTERS:
+        print "ERROR ! cluster %s not found " % str(cluster)
+        print "        valid clusters are " + str(self.CLUSTERS)
+        return None
+    if self.global_shell_config['clustername']:
+        LOG.debug("old cluster = " + self.global_shell_config['clustername'])
+        self.global_shell_config['clustername'] = str(cluster)
+    else:
+        self.global_shell_config['clustername'] = cluster
+    self.prompt = "ambari-" + \
+        str(self.global_shell_config['clustername']) + ">"
+
+
+def help_connect_cluster(self):
+    print '\n'.join([' Usage:', '     connect_cluster <cluster_name>'])
+
+
+def do_disconnect_cluster(self, line):
+
+    if self.global_shell_config['clustername']:
+        LOG.debug("old cluster = " + self.global_shell_config['clustername'])
+    self.global_shell_config['clustername'] = None
+    self.prompt = "ambari>"
+
+
+def help_disconnect_cluster(self):
+    print '\n'.join([' Usage:', '     disconnect_cluster'])
+
+
+def complete_connect_cluster(self, pattern, line, start_index, end_index):
+    if not self.CLUSTERS:
+        clusters = [
+            (c.cluster_name).encode(
+                'ascii',
+                'ignore') for c in self.global_shell_config['client'].get_all_clusters()]
+        self.CLUSTERS = clusters
+
+    LOG.debug(
+        ("self.CLUSTERS = %s pattern = %s ") %
+        (str(
+            self.CLUSTERS),
+            pattern))
+    if pattern:
+        return [
+            c for c in self.CLUSTERS if c.startswith(pattern)]
+    else:
+        return self.CLUSTERS

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/create_cluster.py
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/create_cluster.py b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/create_cluster.py
new file mode 100644
index 0000000..f9947d7
--- /dev/null
+++ b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/create_cluster.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+#
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the  License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+
+import logging
+import textwrap
+
+
+LOG = logging.getLogger(__name__)
+
+
+def do_create_cluster(self, line):
+    #  logging = self.LOG
+    print "TODO"
+    self.prompt = "ambari>"
+
+
+def help_create_cluster(self):
+    print '\n'.join([' Usage:', '     create_cluster <cluster_name>'])

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/service.py
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/service.py b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/service.py
new file mode 100644
index 0000000..d44769a
--- /dev/null
+++ b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/service.py
@@ -0,0 +1,125 @@
+#!/usr/bin/env python
+#
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+
+import logging
+import textwrap
+
+
+LOG = logging.getLogger(__name__)
+
+
+def do_start_service(self, service):
+    if not service:
+        self.help_stop_service()
+        return None
+    clustername = self.global_shell_config['clustername']
+    if not clustername:
+        print("Error! No cluster currently selected")
+        return None
+
+    if self.t_service_action(service=service, action="start"):
+        print("%s is being started" % (service))
+    else:
+        print("Error! cannot start service")
+    return
+
+
+def do_stop_service(self, service):
+    if not service:
+        self.help_start_service()
+        return None
+
+    clustername = self.global_shell_config['clustername']
+    if not clustername:
+        print("Error! No cluster currently selected")
+        return None
+
+    if self.t_service_action(service=service, action="stop"):
+        print("%s is being stopped" % (service))
+    else:
+        print("Error! cannot stop service")
+        return
+
+
+def help_stop_service(self):
+    print textwrap.dedent("""
+    Usage:
+        > stop_service <service_name>
+    """)
+
+
+def help_start_service(self):
+    print textwrap.dedent("""
+    Usage:
+        > start_service <service_name>
+    """)
+
+
+def complete_start_service(self, pattern, line, start_index, end_index):
+    return self.services_complete(pattern, line, start_index, end_index)
+
+
+def complete_stop_service(self, pattern, line, start_index, end_index):
+    client = self.global_shell_config['client']
+    clustername = self.global_shell_config['clustername']
+    if not clustername:
+        return None
+    else:
+        if not self.SERVICES:
+            services = [
+                s.service_name for s in client.get_cluster(clustername).get_all_services()]
+            self.SERVICES = services
+
+    if pattern:
+        return [s for s in self.SERVICES if s.startswith(pattern)]
+    else:
+        return self.SERVICES
+
+
+def services_complete(self, pattern, line, start_index, end_index, append=[]):
+    client = self.global_shell_config['client']
+    clustername = self.global_shell_config['clustername']
+    if not clustername:
+        return None
+    else:
+        if not self.SERVICES:
+            services = [
+                s.service_name for s in client.get_cluster(clustername).get_all_services()]
+            self.SERVICES = services
+
+    if pattern:
+        return [s for s in self.SERVICES + append if s.startswith(pattern)]
+    else:
+        return self.SERVICES + append
+
+
+def t_service_action(self, service, action):
+    try:
+        client = self.global_shell_config['client']
+        cluster = self.global_shell_config['clustername']
+        service = client.get_cluster(cluster).get_service(service)
+    except Exception:
+        print("Service not found")
+        return None
+
+    if action == "start":
+        service.start(message='started by Ambari python CLI')
+    if action == "stop":
+        service.stop(message='stopped by Ambari python CLI')
+    return True

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/shell_config.py
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/shell_config.py b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/shell_config.py
new file mode 100644
index 0000000..2facd02
--- /dev/null
+++ b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/shell_config.py
@@ -0,0 +1,77 @@
+#!/usr/bin/env python
+#
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+import logging
+import textwrap
+
+LOG = logging.getLogger(__name__)
+
+
+def do_get_shell_config(self, config_name):
+    rows = []
+    headers = ["KEY", "VAlUE"]
+    if not config_name:
+        for i in self.global_shell_config.items():
+            rows.append([i[0], i[1]])
+    else:
+        if config_name in self.global_shell_config.keys():
+            rows.append([config_name, self.global_shell_config[config_name]])
+
+    self.generate_output(headers, rows)
+
+
+def do_set_shell_config(self, config=None):
+    kv = config.split(" ")
+    if len(kv) != 2:
+        self.help_set_shell_config()
+        return
+    config_name = kv[0]
+    config_value = kv[1]
+    if config_name in self.global_shell_config.keys():
+        self.global_shell_config[config_name] = config_value
+
+    self.do_get_shell_config(config_name=None)
+
+
+def help_get_shell_config(self):
+    print textwrap.dedent("""
+    Usage:
+        > get_shell_config <config_name>     get all shell config
+    """)
+
+
+def help_set_shell_config(self):
+    print textwrap.dedent("""
+    Usage:
+        > set_shell_config <config_name> <config_value>     sets shell config
+    """)
+
+
+def complete_get_shell_config(self, pattern, line, start_index, end_index):
+    if pattern:
+        return [
+            c for c in self.global_shell_config.keys() if c.startswith(pattern)]
+    else:
+        return self.CLUSTERS
+
+
+def complete_set_shell_config(self, pattern, line, start_index, end_index):
+    if pattern:
+        return [
+            c for c in self.global_shell_config.keys() if c.startswith(pattern)]
+    else:
+        return self.CLUSTERS

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/show.py
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/show.py b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/show.py
new file mode 100644
index 0000000..584b40a
--- /dev/null
+++ b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/plugins/show.py
@@ -0,0 +1,155 @@
+#!/usr/bin/env python
+#
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+
+import logging
+import textwrap
+
+LOG = logging.getLogger(__name__)
+
+
+def help_show(self):
+    print textwrap.dedent("""
+    Usage:
+        > show clusters     list clusters
+        > show hosts        list hosts
+        > show stacks       list stacks
+        > show services     list services
+        > show requests     list previous requests
+        > show blueprints   list blueprints
+    """)
+
+
+def do_show(self, option):
+    """
+    Usage:
+        > show clusters     list clusters
+        > show hosts        list hosts
+        > show stacks       list stacks
+        > show services     list services
+        > show requests     list previous requests
+        > show blueprints   list blueprints
+    """
+    headers = []
+    rows = []
+    options = [
+        "clusters",
+        "stacks",
+        "status",
+        "services",
+        "hosts",
+        "requests",
+        "blueprints"]
+
+    if not option:
+        self.help_show()
+        return
+
+    if option not in options:
+        self.default(option)
+        return
+
+    client = self.global_shell_config['client']
+    clustername = self.global_shell_config['clustername']
+    # show clusters
+    if option == "clusters":
+        "Display list of clusters on system"
+        headers = ["CLUSTER NAME"]
+        clusters = client.get_all_clusters()
+        for cluster in clusters:
+            rows.append([cluster.cluster_name])
+
+    # show clusters
+    if option == "stacks":
+        "Display list of stacks on system"
+        headers = ["STACK NAME"]
+        stacks = client.get_stacks(True)
+        for stack in stacks:
+            rows.append([stack.stack_version])
+
+    if option == "blueprints":
+        "Display list of blueprints on system"
+        headers = ["BLUEPRINT NAME", "VERSION"]
+        blues = client.get_blueprint()
+        for b in blues:
+            rows.append([b.blueprint_name, b.stack_version])
+
+    if option == "status":
+        "Display list of stacks on system"
+        headers = ["HOST_NAME", "ROLE", "STATUS"]
+        if not clustername:
+            print("Error! No cluster currently selected")
+            return
+        else:
+            tasks = client.get_task_status(clustername, 2)
+            for task in tasks:
+                rows.append([task.host_name, task.role, task.status])
+
+    # show hosts
+    if option == "hosts":
+        "Display a list of hosts avaiable on the system"
+        headers = ["HOSTNAME", "IP ADDRESS"]
+        if not clustername:
+            for host in client.get_all_hosts():
+                rows.append([host.host_name, host.ip])
+        else:
+            c = client.get_cluster(clustername)
+            for host in c.get_all_hosts():
+                rows.append([host.host_name, host.ip])
+
+    if option == "requests":
+        headers = ["REQUEST-ID", "STATUS"]
+        if not clustername:
+            print("Error! No cluster currently selected")
+            return
+        else:
+            c = client.get_cluster(clustername)
+            for req in client.get_requests(clustername):
+                rows.append([req.id, req.request_status])
+
+    # show services
+    if option == "services":
+        "Show list of services on the cluster"
+        headers = ["SERVICE", "STATUS"]
+
+        if not clustername:
+            print("Error! No cluster currently selected")
+            return
+        else:
+            c = client.get_cluster(clustername)
+            for service in c.get_all_services():
+                rows.append([service.service_name, service.state])
+
+    self.generate_output(headers, rows)
+
+
+def complete_show(self, pattern, line, start_index, end_index):
+    show_commands = [
+        "clusters",
+        "hosts",
+        "services",
+        "stacks",
+        "blueprints",
+        "requests"]
+    if pattern:
+        return [c for c in show_commands if c.startswith(pattern)]
+    else:
+        return show_commands
+
+if __name__ == '__main__':
+    do_show(None, None)

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/utils/__init__.py
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/utils/__init__.py b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/utils/__init__.py
new file mode 100644
index 0000000..278df2e
--- /dev/null
+++ b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/utils/__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.

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/utils/displayutils.py
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/utils/displayutils.py b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/utils/displayutils.py
new file mode 100644
index 0000000..3c45e7f
--- /dev/null
+++ b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/utils/displayutils.py
@@ -0,0 +1,128 @@
+#!/usr/bin/env python
+#
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+import logging
+import textwrap
+import cStringIO
+import operator
+from xml.etree import ElementTree as etree
+from functools import reduce
+
+
+LOG = logging.getLogger(__name__)
+
+
+class bcolors:
+    HEADER = '\033[95m'
+    OKBLUE = '\033[94m'
+    OKGREEN = '\033[92m'
+    WARNING = '\033[93m'
+    FAIL = '\033[91m'
+    ENDC = '\033[0m'
+
+    def disable(self):
+        self.HEADER = ''
+        self.OKBLUE = ''
+        self.OKGREEN = ''
+        self.WARNING = ''
+        self.FAIL = ''
+
+
+__header__ = textwrap.dedent("""
+   ___         __            _
+  / _ | __ _  / /  ___ _____(_)
+ / __ |/  ' \/ _ \/ _ `/ __/ /
+/_/ |_/_/_/_/_.__/\_,_/_/ /_/  CLI v%s
+""" % str(1))
+
+
+def shellBanner():
+    """
+     Prints the CLI Banner.
+    """
+    return __header__ + textwrap.dedent(
+        """
+    ====================================
+        Welcome to Ambari python CLI
+        type 'help' to list all commands..
+    ====================================
+    """)
+
+
+def createXML(headers, rows):
+    root = etree.Element('xmloutput')
+    for r in rows:
+        for h, relemt in zip(headers, r):
+
+            child = etree.Element(h.lower().replace(' ', '_'))
+            child.text = str(relemt)
+            root.append(child)
+
+    # pretty string
+    s = etree.tostring(root)
+    return s
+
+
+def createCSV(headers, rows):
+    headers = [x.lower().replace(' ', '_') for x in headers]
+    print(','.join(headers))
+    for r in rows:
+        print(','.join(r))
+
+
+def display_table(headers, rows):
+
+    delimiter = '='
+    delimiter1 = ' | '
+    output = cStringIO.StringIO()
+    temp_rows = [tuple(headers)] + rows
+    row_tuple = [(row,) for row in temp_rows]
+    # get max width
+    verticalrows = map(None, *reduce(operator.add, row_tuple))
+
+    if not rows:
+        widthList = [len(str(x)) for x in headers]
+        row_width = sum(widthList)
+    else:
+        widthList = [max([len(str(x)) for x in column])
+                     for column in verticalrows]
+        row_width = sum(widthList)
+    header_line = delimiter * \
+        (row_width + len(delimiter1) * (len(widthList) - 1))
+
+    i = 0
+    for rr in row_tuple:
+        for row in rr:
+            print >> output, delimiter1.join(
+                [(str(x)).ljust(width) for (x, width) in zip(row, widthList)])
+        if i == 0:
+            print >> output, header_line
+            i = 9999
+    return output.getvalue()
+
+
+if __name__ == '__main__':
+    print createXML(['STACK NAME', ], [[u'HDP']])
+    createCSV(['STACK NAME', ], [[u'HDP']])
+    headers = ['First Name', 'Last Name', 'Age']
+    data = \
+        '''Sam ,Browne,21
+       Jhon,Browne,23
+       Adam,senio,21'''
+    rows = [row.strip().split(',') for row in data.splitlines()]
+    print display_table(headers, rows)

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/utils/osutils.py
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/utils/osutils.py b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/utils/osutils.py
new file mode 100644
index 0000000..8aeaa34
--- /dev/null
+++ b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/utils/osutils.py
@@ -0,0 +1,69 @@
+#!/usr/bin/env python
+#
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+import logging
+import os
+import sys
+import platform
+
+LOG = logging.getLogger(__name__)
+
+
+def clearScreen(operatingSys):
+    """
+    Function to clear the screen
+    Input   : OS
+    """
+    logging.info('Entering..')
+
+    if operatingSys == 'Windows':
+        cmdClear = 'CLS'
+    elif operatingSys == 'Linux':
+        cmdClear = 'clear'
+    elif operatingSys == 'Darwin':
+        cmdClear = 'clear'
+    logging.debug('Running command : %s', cmdClear)
+    os.system(cmdClear)
+    logging.info('Exiting..')
+
+
+def getOperatingSystem():
+    logging.info('Entering..')
+    operatingSys = platform.system()
+    # sprint operatingSys
+    if not operatingSys:
+        logging.error('Operating system is NULL.')
+        return False, ''
+    else:
+        logging.debug('Got operating system : %s', operatingSys)
+        logging.info('Exiting..')
+        return True, operatingSys
+
+
+def doclearScreen():
+    # Determine the OS
+    result, operatingSys = getOperatingSystem()
+    if not result:
+        logging.error('Failed to determine Operating System. Exiting.')
+        sys.exit(1)
+    # clear the Screen
+    clearScreen(operatingSys)
+
+
+if __name__ == '__main__':
+    pass

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/utils/pluginutils.py
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/utils/pluginutils.py b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/utils/pluginutils.py
new file mode 100644
index 0000000..fdcb97c
--- /dev/null
+++ b/ambari-shell/ambari-python-shell/src/main/python/ambari_shell/utils/pluginutils.py
@@ -0,0 +1,100 @@
+#!/usr/bin/env python
+#
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+import logging
+import os
+import sys
+import inspect
+
+LOG = logging.getLogger(__name__)
+#------------------------------------------------------------------------------
+'''
+Function that searches for all plugins from a file
+Input   : folder
+Output  : dict
+'''
+#------------------------------------------------------------------------------
+
+
+def get_plugins(module):
+    logging.debug('[Module: %s]\n' % module.__name__)
+
+    plugin_method_map = {}
+    count = 0
+
+    for name in dir(module):
+        obj = getattr(module, name)
+        if inspect.isclass(obj):
+            count += 1
+        elif (inspect.ismethod(obj) or inspect.isfunction(obj)):
+            if obj.__name__.startswith("do_") or obj.__name__.startswith(
+                    "help_") or obj.__name__.startswith("complete_") or obj.__name__.startswith("t_"):
+                logging.debug("%s ,%s ", obj.__name__, obj)
+                plugin_method_map.update({obj.__name__: obj})
+                count += 1
+            elif inspect.isbuiltin(obj):
+                count += 1
+    logging.debug(plugin_method_map)
+    if count == 0:
+        logging.debug('(No members)')
+
+    return plugin_method_map
+
+
+def import_modules(dirr):
+    module_list = []
+    for f in os.listdir(os.path.abspath(dirr)):
+        module_name, ext = os.path.splitext(f)
+        if ext == '.py' and module_name != "ambari_shell":
+            logging.debug('imported module: %s' % (module_name))
+            module = __import__(module_name)
+            module_list.append(module)
+
+    return module_list
+
+
+def getPlugins(foldername):
+    if os.path.isdir(foldername):
+        sys.path.append(foldername)
+        logging.debug('%s is a directory!' % (foldername))
+
+    mod_list = import_modules(foldername)
+    logging.debug(mod_list)
+
+    plugin_method_map = {}
+    for m in mod_list:
+        dictt = get_plugins(m)
+        if dictt:
+            plugin_method_map.update(dictt)
+
+    return plugin_method_map
+
+
+def getPluginsFromModules(modulename):
+    module = __import__(modulename)
+    logging.debug(module)
+
+    plugin_method_map = {}
+    dictt = get_plugins(module)
+    if dictt:
+        plugin_method_map.update(dictt)
+
+    return plugin_method_map
+
+if __name__ == "__main__":
+    print getPlugins("plug")

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-python-shell/src/main/python/setup.py
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-python-shell/src/main/python/setup.py b/ambari-shell/ambari-python-shell/src/main/python/setup.py
new file mode 100755
index 0000000..b67d872
--- /dev/null
+++ b/ambari-shell/ambari-python-shell/src/main/python/setup.py
@@ -0,0 +1,40 @@
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+
+from setuptools import setup, find_packages
+
+from sys import version_info, platform
+
+if version_info[:2] > (2, 5):
+    install_requires = []
+else:
+    install_requires = ['simplejson >= 2.0.0']
+
+# Python 2.6 and below requires argparse
+if version_info[:2] < (2, 7):
+    install_requires += ['argparse']
+
+install_requires += ['ambari_client']
+setup(
+  name='ambari_shell',
+  author_email="ambari-dev@incubator.apache.org",
+  version="1.6.0-SNAPSHOT",
+  packages=['ambari_shell'],
+  install_requires=install_requires,
+  description='Ambari Python Shell',
+  license='Apache License 2.0'
+)

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/ambari-python-shell/src/packages/tarball/all.xml
----------------------------------------------------------------------
diff --git a/ambari-shell/ambari-python-shell/src/packages/tarball/all.xml b/ambari-shell/ambari-python-shell/src/packages/tarball/all.xml
new file mode 100755
index 0000000..0e4f34b
--- /dev/null
+++ b/ambari-shell/ambari-python-shell/src/packages/tarball/all.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+-->
+<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.1"
+          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+          xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.1 http://maven.apache.org/xsd/assembly-1.1.1.xsd">
+  <!--This 'all' id is not appended to the produced bundle because we do this:
+    http://maven.apache.org/plugins/maven-assembly-plugin/faq.html#required-classifiers
+  -->
+  <formats>
+    <format>dir</format>
+  </formats>
+  <includeBaseDirectory>false</includeBaseDirectory>
+  <fileSets>
+    <fileSet>
+      <directory>src/main/python</directory>
+      <outputDirectory>/</outputDirectory>
+    </fileSet>
+  </fileSets>
+</assembly>

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/assemblies/client.xml
----------------------------------------------------------------------
diff --git a/ambari-shell/assemblies/client.xml b/ambari-shell/assemblies/client.xml
new file mode 100644
index 0000000..20670cd
--- /dev/null
+++ b/ambari-shell/assemblies/client.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+  
+       http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<assembly>
+</assembly>

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/pom.xml
----------------------------------------------------------------------
diff --git a/ambari-shell/pom.xml b/ambari-shell/pom.xml
index a7e3400..947c9b9 100644
--- a/ambari-shell/pom.xml
+++ b/ambari-shell/pom.xml
@@ -1,14 +1,23 @@
 <?xml version="1.0"?>
-<!-- Licensed under the Apache License, Version 2.0 (the "License"); you
-  may not use this file except in compliance with the License. You may obtain
-  a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless
-  required by applicable law or agreed to in writing, software distributed
-  under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
-  OR CONDITIONS OF ANY KIND, either express or implied. See the License for
-  the specific language governing permissions and limitations under the License.
-  See accompanying LICENSE file. -->
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <!--
+   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.
+-->
+
   <parent>
     <groupId>org.apache.ambari</groupId>
     <artifactId>ambari-project</artifactId>
@@ -18,106 +27,33 @@
   <modelVersion>4.0.0</modelVersion>
   <groupId>org.apache.ambari</groupId>
   <artifactId>ambari-shell</artifactId>
-  <packaging>jar</packaging>
-  <name>Ambari Shell</name>
+  <packaging>pom</packaging>
   <version>1.3.0-SNAPSHOT</version>
+  <name>Ambari Shell</name>
   <description>Ambari Shell</description>
-  <properties>
-    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-    <start-class>org.apache.ambari.shell.AmbariShell</start-class>
-  </properties>
-  <dependencies>
-    <dependency>
-      <groupId>junit</groupId>
-      <artifactId>junit</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.springframework.shell</groupId>
-      <artifactId>spring-shell</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.springframework.boot</groupId>
-      <artifactId>spring-boot-starter</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.springframework.boot</groupId>
-      <artifactId>spring-boot-starter-test</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>com.github.lalyos</groupId>
-      <artifactId>jfiglet</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>commons-io</groupId>
-      <artifactId>commons-io</artifactId>
-      <version>2.3</version>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.ambari</groupId>
-      <artifactId>groovy-client</artifactId>
-      <version>1.3.0-SNAPSHOT</version>
-    </dependency>
-    <dependency>
-      <groupId>org.mockito</groupId>
-      <artifactId>mockito-core</artifactId>
-      <version>1.9.5</version>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>jline</groupId>
-      <artifactId>jline</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.codehaus.jackson</groupId>
-      <artifactId>jackson-mapper-asl</artifactId>
-    </dependency>
-  </dependencies>
+  <modules>
+    <module>ambari-python-shell</module>
+    <module>ambari-groovy-shell</module>
+  </modules>
   <build>
     <plugins>
       <plugin>
-        <artifactId>maven-compiler-plugin</artifactId>
-        <version>3.0</version>
-      </plugin>
-      <plugin>
-        <groupId>org.apache.rat</groupId>
-        <artifactId>apache-rat-plugin</artifactId>
-        <configuration>
-          <excludes>
-            <exclude>src/main/resources/elephant.txt</exclude>
-            <exclude>src/test/resources/2columns</exclude>
-            <exclude>src/test/resources/3columns</exclude>
-            <exclude>src/test/resources/testBlueprint.json</exclude>
-          </excludes>
-        </configuration>
-        <executions>
-          <execution>
-            <phase>test</phase>
-            <goals>
-              <goal>check</goal>
-            </goals>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
         <artifactId>maven-assembly-plugin</artifactId>
         <configuration>
-          <skipAssembly>true</skipAssembly>
+          <tarLongFileMode>gnu</tarLongFileMode>
+          <descriptors>
+            <descriptor>assemblies/client.xml</descriptor>
+          </descriptors>
         </configuration>
-      </plugin>
-      <plugin>
-        <groupId>org.springframework.boot</groupId>
-        <artifactId>spring-boot-maven-plugin</artifactId>
-        <version>1.0.2.RELEASE</version>
         <executions>
           <execution>
+            <id>build-tarball</id>
+            <phase>prepare-package</phase>
             <goals>
-              <goal>repackage</goal>
+              <goal>single</goal>
             </goals>
           </execution>
         </executions>
-        <configuration>
-          <mainClass>${start-class}</mainClass>
-        </configuration>
       </plugin>
       <plugin>
         <groupId>org.vafer</groupId>
@@ -132,9 +68,7 @@
           </execution>
         </executions>
         <configuration>
-          <controlDir>${basedir}/../../ambari-project/src/main/package/deb/control</controlDir>
-          <skip>true</skip>
-          <submodules>false</submodules>
+          <controlDir>${basedir}/../ambari-project/src/main/package/deb/control</controlDir>
         </configuration>
       </plugin>
     </plugins>

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/src/main/java/org/apache/ambari/shell/AmbariShell.java
----------------------------------------------------------------------
diff --git a/ambari-shell/src/main/java/org/apache/ambari/shell/AmbariShell.java b/ambari-shell/src/main/java/org/apache/ambari/shell/AmbariShell.java
deleted file mode 100644
index e842620..0000000
--- a/ambari-shell/src/main/java/org/apache/ambari/shell/AmbariShell.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.ambari.shell;
-
-import org.apache.ambari.groovy.client.AmbariClient;
-import org.apache.ambari.shell.model.AmbariContext;
-import org.apache.ambari.shell.model.Hints;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.CommandLineRunner;
-import org.springframework.boot.builder.SpringApplicationBuilder;
-import org.springframework.context.annotation.ComponentScan;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.shell.CommandLine;
-import org.springframework.shell.core.JLineShellComponent;
-import org.springframework.shell.event.ShellStatus;
-import org.springframework.shell.event.ShellStatusListener;
-
-/**
- * Shell bootstrap.
- */
-@Configuration
-@ComponentScan(basePackageClasses = {AmbariShell.class})
-public class AmbariShell implements CommandLineRunner, ShellStatusListener {
-
-  @Autowired
-  private CommandLine commandLine;
-  @Autowired
-  private JLineShellComponent shell;
-  @Autowired
-  private AmbariContext context;
-  @Autowired
-  private AmbariClient client;
-
-  @Override
-  public void run(String... arg) throws Exception {
-    String[] shellCommandsToExecute = commandLine.getShellCommandsToExecute();
-    if (shellCommandsToExecute != null) {
-      for (String cmd : shellCommandsToExecute) {
-        if (!shell.executeScriptLine(cmd)) {
-          break;
-        }
-      }
-      System.exit(0);
-    } else {
-      shell.addShellStatusListener(this);
-      shell.start();
-      shell.promptLoop();
-      shell.waitForComplete();
-    }
-  }
-
-  @Override
-  public void onShellStatusChange(ShellStatus oldStatus, ShellStatus newStatus) {
-    if (newStatus.getStatus() == ShellStatus.Status.STARTED) {
-      try {
-        String cluster = client.getClusterName();
-        boolean available = client.isBlueprintAvailable();
-        if (cluster == null) {
-          if (available) {
-            context.setHint(Hints.BUILD_CLUSTER);
-          } else {
-            context.setHint(Hints.ADD_BLUEPRINT);
-          }
-        } else {
-          context.setHint(Hints.PROGRESS);
-        }
-        context.setCluster(cluster);
-        context.setBlueprintsAvailable(available);
-      } catch (Exception e) {
-        System.out.println(e.getMessage());
-        shell.executeCommand("quit");
-      }
-    }
-  }
-
-
-  public static void main(String[] args) {
-    if (args.length == 0) {
-      System.out.println(
-        "\nAmbari Shell: Interactive command line tool for managing Apache Ambari.\n\n" +
-          "Usage:\n" +
-          "  java -jar ambari-shell.jar                  : Starts Ambari Shell in interactive mode.\n" +
-          "  java -jar ambari-shell.jar --cmdfile=<FILE> : Ambari Shell executes commands read from the file.\n\n" +
-          "Options:\n" +
-          "  --ambari.host=<HOSTNAME>       Hostname of the Ambari Server [default: localhost].\n" +
-          "  --ambari.port=<PORT>           Port of the Ambari Server [default: 8080].\n" +
-          "  --ambari.user=<USER>           Username of the Ambari admin [default: admin].\n" +
-          "  --ambari.password=<PASSWORD>   Password of the Ambari admin [default: admin].\n\n" +
-          "Note:\n" +
-          "  At least one option is mandatory."
-      );
-      System.exit(1);
-    }
-    new SpringApplicationBuilder(AmbariShell.class).showBanner(false).run(args);
-  }
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/src/main/java/org/apache/ambari/shell/commands/BasicCommands.java
----------------------------------------------------------------------
diff --git a/ambari-shell/src/main/java/org/apache/ambari/shell/commands/BasicCommands.java b/ambari-shell/src/main/java/org/apache/ambari/shell/commands/BasicCommands.java
deleted file mode 100644
index 9babe12..0000000
--- a/ambari-shell/src/main/java/org/apache/ambari/shell/commands/BasicCommands.java
+++ /dev/null
@@ -1,207 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.ambari.shell.commands;
-
-import static org.apache.ambari.shell.support.TableRenderer.renderMapValueMap;
-import static org.apache.ambari.shell.support.TableRenderer.renderSingleMap;
-
-import org.apache.ambari.groovy.client.AmbariClient;
-import org.apache.ambari.shell.model.AmbariContext;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.shell.core.CommandMarker;
-import org.springframework.shell.core.annotation.CliAvailabilityIndicator;
-import org.springframework.shell.core.annotation.CliCommand;
-import org.springframework.shell.core.annotation.CliOption;
-import org.springframework.stereotype.Component;
-
-/**
- * Basic commands used in the shell. Delegating the commands
- * to the Ambari Server via a Groovy based client.
- *
- * @see org.apache.ambari.groovy.client.AmbariClient
- */
-@Component
-public class BasicCommands implements CommandMarker {
-
-  private AmbariClient client;
-  private AmbariContext context;
-
-  @Autowired
-  public BasicCommands(AmbariClient client, AmbariContext context) {
-    this.client = client;
-    this.context = context;
-  }
-
-  /**
-   * Checks whether the tasks command is available or not.
-   *
-   * @return true if its available false otherwise
-   */
-  @CliAvailabilityIndicator("tasks")
-  public boolean isTasksCommandAvailable() {
-    return context.isConnectedToCluster();
-  }
-
-  /**
-   * Prints the tasks of the Ambari Server.
-   *
-   * @param id id of the request
-   * @return task list
-   */
-  @CliCommand(value = "tasks", help = "Lists the Ambari tasks")
-  public String tasks(
-    @CliOption(key = "id", mandatory = false, help = "Id of the request; default is: 1", unspecifiedDefaultValue = "1") String id) {
-    return renderSingleMap(client.getTaskMap(id), "TASK", "STATUS");
-  }
-
-  /**
-   * Checks whether the service list command is available or not.
-   *
-   * @return true if available false otherwise
-   */
-  @CliAvailabilityIndicator("services list")
-  public boolean isServiceListCommandAvailable() {
-    return context.isConnectedToCluster();
-  }
-
-  /**
-   * Prints the available service list of the Ambari Server.
-   *
-   * @return service list
-   */
-  @CliCommand(value = "services list", help = "Lists the available services")
-  public String servicesList() {
-    return renderSingleMap(client.getServicesMap(), "SERVICE", "STATE");
-  }
-
-  /**
-   * Checks whether the service components command is available or not.
-   *
-   * @return true if available false otherwise
-   */
-  @CliAvailabilityIndicator("services components")
-  public boolean isServiceComponentsCommandAvailable() {
-    return context.isConnectedToCluster();
-  }
-
-  /**
-   * Prints the service components of the Ambari Server.
-   *
-   * @return service component list
-   */
-  @CliCommand(value = "services components", help = "Lists all services with their components")
-  public String serviceComponents() {
-    return renderMapValueMap(client.getServiceComponentsMap(), "SERVICE", "COMPONENT", "STATE");
-  }
-
-  /**
-   * Checks whether the debug on command is available or not.
-   *
-   * @return true if available false otherwise
-   */
-  @CliAvailabilityIndicator("debug on")
-  public boolean isDebugOnCommandAvailable() {
-    return !client.isDebugEnabled();
-  }
-
-  /**
-   * Turns the debug on. From now on users will see the URLs of the API calls.
-   *
-   * @return status message
-   */
-  @CliCommand(value = "debug on", help = "Shows the URL of the API calls")
-  public String debugOn() {
-    client.setDebugEnabled(true);
-    return "debug enabled";
-  }
-
-  /**
-   * Checks whether the debug off command is available or not.
-   *
-   * @return true if available false otherwise
-   */
-  @CliAvailabilityIndicator("debug off")
-  public boolean isDebugOffCommandAvailable() {
-    return client.isDebugEnabled();
-  }
-
-  /**
-   * Turns the debug off. URLs are not visible anymore.
-   *
-   * @return status message
-   */
-  @CliCommand(value = "debug off", help = "Stops showing the URL of the API calls")
-  public String debugOff() {
-    client.setDebugEnabled(false);
-    return "debug disabled";
-  }
-
-  /**
-   * Checks whether the hint command is available or not.
-   *
-   * @return true if available false otherwise
-   */
-  @CliAvailabilityIndicator("hint")
-  public boolean isHintCommandAvailable() {
-    return true;
-  }
-
-  /**
-   * Provides some hints what you can do in the current context.
-   *
-   * @return hint message
-   */
-  @CliCommand(value = "hint", help = "Shows some hints")
-  public String hint() {
-    return context.getHint();
-  }
-
-  @CliAvailabilityIndicator("services stop")
-  public boolean isServiceStopCommandAvailable() {
-    return context.isConnectedToCluster();
-  }
-
-  @CliCommand(value = "services stop", help = "Stops all the running services")
-  public String stopServices() {
-    String message;
-    try {
-      client.stopAllServices();
-      message = "Stopping all services..";
-    } catch (Exception e) {
-      message = "Cannot stop services";
-    }
-    return String.format("%s\n\n%s", message, servicesList());
-  }
-
-  @CliAvailabilityIndicator("services start")
-  public boolean isServiceStartCommandAvailable() {
-    return context.isConnectedToCluster();
-  }
-
-  @CliCommand(value = "services start", help = "Starts all the services")
-  public String startServices() {
-    String message;
-    try {
-      client.startAllServices();
-      message = "Starting all services..";
-    } catch (Exception e) {
-      message = "Cannot start services";
-    }
-    return String.format("%s\n\n%s", message, servicesList());
-  }
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/src/main/java/org/apache/ambari/shell/commands/BlueprintCommands.java
----------------------------------------------------------------------
diff --git a/ambari-shell/src/main/java/org/apache/ambari/shell/commands/BlueprintCommands.java b/ambari-shell/src/main/java/org/apache/ambari/shell/commands/BlueprintCommands.java
deleted file mode 100644
index 73000d0..0000000
--- a/ambari-shell/src/main/java/org/apache/ambari/shell/commands/BlueprintCommands.java
+++ /dev/null
@@ -1,198 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.ambari.shell.commands;
-
-import static org.apache.ambari.shell.support.TableRenderer.renderMultiValueMap;
-import static org.apache.ambari.shell.support.TableRenderer.renderSingleMap;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.net.URL;
-
-import org.apache.ambari.groovy.client.AmbariClient;
-import org.apache.ambari.shell.completion.Blueprint;
-import org.apache.ambari.shell.model.AmbariContext;
-import org.apache.ambari.shell.model.Hints;
-import org.apache.commons.io.IOUtils;
-import org.codehaus.jackson.map.ObjectMapper;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.shell.core.CommandMarker;
-import org.springframework.shell.core.annotation.CliAvailabilityIndicator;
-import org.springframework.shell.core.annotation.CliCommand;
-import org.springframework.shell.core.annotation.CliOption;
-import org.springframework.stereotype.Component;
-
-/**
- * Blueprint related commands used in the shell.
- *
- * @see org.apache.ambari.groovy.client.AmbariClient
- */
-@Component
-public class BlueprintCommands implements CommandMarker {
-
-  private AmbariClient client;
-  private AmbariContext context;
-  private ObjectMapper jsonMapper;
-
-  @Autowired
-  public BlueprintCommands(AmbariClient client, AmbariContext context, ObjectMapper jsonMapper) {
-    this.client = client;
-    this.context = context;
-    this.jsonMapper = jsonMapper;
-  }
-
-  /**
-   * Checks whether the blueprints command is available or not.
-   *
-   * @return true if available false otherwise
-   */
-  @CliAvailabilityIndicator("blueprint list")
-  public boolean isBlueprintListCommandAvailable() {
-    return context.areBlueprintsAvailable();
-  }
-
-  /**
-   * Prints all the blueprints.
-   *
-   * @return list of blueprints
-   */
-  @CliCommand(value = "blueprint list", help = "Lists all known blueprints")
-  public String listBlueprints() {
-    return renderSingleMap(client.getBlueprintsMap(), "BLUEPRINT", "STACK");
-  }
-
-  /**
-   * Checks whether the blueprint show command is available or not.
-   *
-   * @return true if available false otherwise
-   */
-  @CliAvailabilityIndicator(value = "blueprint show")
-  public boolean isBlueprintShowCommandAvailable() {
-    return context.areBlueprintsAvailable();
-  }
-
-  /**
-   * Shows the requested blueprint's details.
-   *
-   * @param id id of the blueprint
-   * @return blueprint as formatted table
-   */
-  @CliCommand(value = "blueprint show", help = "Shows the blueprint by its id")
-  public String showBlueprint(
-    @CliOption(key = "id", mandatory = true, help = "Id of the blueprint") Blueprint id) {
-    return renderMultiValueMap(client.getBlueprintMap(id.getName()), "HOSTGROUP", "COMPONENT");
-  }
-
-  /**
-   * Checks whether the blueprint add command is available or not.
-   *
-   * @return true if available false otherwise
-   */
-  @CliAvailabilityIndicator(value = "blueprint add")
-  public boolean isBlueprintAddCommandAvailable() {
-    return true;
-  }
-
-  /**
-   * Adds a blueprint to the Ambari server either through an URL or from a file.
-   * If both specified the file takes precedence.
-   *
-   * @param url  -optional, URL containing the blueprint json
-   * @param file - optional, file containing the blueprint json
-   * @return status message
-   */
-  @CliCommand(value = "blueprint add", help = "Add a new blueprint with either --url or --file")
-  public String addBlueprint(
-    @CliOption(key = "url", mandatory = false, help = "URL of the blueprint to download from") String url,
-    @CliOption(key = "file", mandatory = false, help = "File which contains the blueprint") File file) {
-    String message;
-    try {
-      String json = file == null ? readContent(url) : readContent(file);
-      if (json != null) {
-        client.addBlueprint(json);
-        context.setHint(Hints.BUILD_CLUSTER);
-        context.setBlueprintsAvailable(true);
-        message = String.format("Blueprint: '%s' has been added", getBlueprintName(json));
-      } else {
-        message = "No blueprint specified";
-      }
-    } catch (Exception e) {
-      message = "Cannot add blueprint: " + e.getMessage();
-    }
-    return message;
-  }
-
-  /**
-   * Checks whether the blueprint defaults command is available or not.
-   *
-   * @return true if available false otherwise
-   */
-  @CliAvailabilityIndicator(value = "blueprint defaults")
-  public boolean isBlueprintDefaultsAddCommandAvailable() {
-    return !context.areBlueprintsAvailable();
-  }
-
-  /**
-   * Adds two default blueprints to the Ambari server.
-   *
-   * @return status message
-   */
-  @CliCommand(value = "blueprint defaults", help = "Adds the default blueprints to Ambari")
-  public String addBlueprint() {
-    String message = "Default blueprints added";
-    try {
-      client.addDefaultBlueprints();
-      context.setHint(Hints.BUILD_CLUSTER);
-      context.setBlueprintsAvailable(true);
-    } catch (Exception e) {
-      message = "Failed to add the default blueprints: " + e.getMessage();
-    }
-    return message;
-  }
-
-  private String readContent(File file) {
-    String content = null;
-    try {
-      content = IOUtils.toString(new FileInputStream(file));
-    } catch (IOException e) {
-      // not important
-    }
-    return content;
-  }
-
-  private String readContent(String url) {
-    String content = null;
-    try {
-      content = IOUtils.toString(new URL(url));
-    } catch (IOException e) {
-      // not important
-    }
-    return content;
-  }
-
-  private String getBlueprintName(String json) {
-    String result = "";
-    try {
-      result = jsonMapper.readTree(json.getBytes()).get("Blueprints").get("blueprint_name").asText();
-    } catch (IOException e) {
-      // not important
-    }
-    return result;
-  }
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/src/main/java/org/apache/ambari/shell/commands/ClusterCommands.java
----------------------------------------------------------------------
diff --git a/ambari-shell/src/main/java/org/apache/ambari/shell/commands/ClusterCommands.java b/ambari-shell/src/main/java/org/apache/ambari/shell/commands/ClusterCommands.java
deleted file mode 100644
index dafdb85..0000000
--- a/ambari-shell/src/main/java/org/apache/ambari/shell/commands/ClusterCommands.java
+++ /dev/null
@@ -1,294 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.ambari.shell.commands;
-
-import static org.apache.ambari.shell.support.TableRenderer.renderMultiValueMap;
-import static org.apache.ambari.shell.support.TableRenderer.renderSingleMap;
-
-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.FocusType;
-import org.apache.ambari.shell.model.Hints;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.shell.core.CommandMarker;
-import org.springframework.shell.core.annotation.CliAvailabilityIndicator;
-import org.springframework.shell.core.annotation.CliCommand;
-import org.springframework.shell.core.annotation.CliOption;
-import org.springframework.stereotype.Component;
-
-import groovyx.net.http.HttpResponseException;
-
-/**
- * Cluster related commands used in the shell.
- *
- * @see org.apache.ambari.groovy.client.AmbariClient
- */
-@Component
-public class ClusterCommands implements CommandMarker {
-
-  private AmbariClient client;
-  private AmbariContext context;
-  private FlashService flashService;
-  private Map<String, List<String>> hostGroups;
-
-  @Autowired
-  public ClusterCommands(AmbariClient client, AmbariContext context, FlashService flashService) {
-    this.client = client;
-    this.context = context;
-    this.flashService = flashService;
-  }
-
-  /**
-   * Checks whether the cluster build command is available or not.
-   *
-   * @return true if available false otherwise
-   */
-  @CliAvailabilityIndicator("cluster build")
-  public boolean isClusterBuildCommandAvailable() {
-    return !context.isConnectedToCluster() && !context.isFocusOnClusterBuild() && context.areBlueprintsAvailable();
-  }
-
-  /**
-   * Sets the focus on cluster building. Takes a blueprint id, if it does not exists it wont focus.
-   * After focus the users are able to assign hosts to host groups.
-   *
-   * @param id id of the blueprint
-   * @return prints the blueprint as formatted table if exists, otherwise error message
-   */
-  @CliCommand(value = "cluster build", help = "Starts to build a cluster")
-  public String buildCluster(
-    @CliOption(key = "blueprint", mandatory = true, help = "Id of the blueprint, use 'blueprints' command to see the list") Blueprint id) {
-    String message;
-    String blueprint = id.getName();
-    if (client.doesBlueprintExist(blueprint)) {
-      context.setFocus(blueprint, FocusType.CLUSTER_BUILD);
-      context.setHint(Hints.ASSIGN_HOSTS);
-      message = String.format("%s\n%s",
-        renderSingleMap(client.getHostNames(), "HOSTNAME", "STATE"),
-        renderMultiValueMap(client.getBlueprintMap(blueprint), "HOSTGROUP", "COMPONENT"));
-      createNewHostGroups();
-    } else {
-      message = "Not a valid blueprint id";
-    }
-    return message;
-  }
-
-  /**
-   * Checks whether the cluster assign command is available or not.
-   *
-   * @return true if available false otherwise
-   */
-  @CliAvailabilityIndicator("cluster assign")
-  public boolean isAssignCommandAvailable() {
-    return context.isFocusOnClusterBuild();
-  }
-
-  /**
-   * Assign hosts to host groups provided in the blueprint.
-   *
-   * @param host  host to assign
-   * @param group which host group to
-   * @return status message
-   */
-  @CliCommand(value = "cluster assign", help = "Assign host to host group")
-  public String assign(
-    @CliOption(key = "host", mandatory = true, help = "Fully qualified host name") Host host,
-    @CliOption(key = "hostGroup", mandatory = true, help = "Host group which to assign the host") String group) {
-    String message;
-    String hostName = host.getName();
-    if (client.getHostNames().keySet().contains(hostName)) {
-      if (addHostToGroup(hostName, group)) {
-        context.setHint(Hints.CREATE_CLUSTER);
-        message = String.format("%s has been added to %s", hostName, group);
-      } else {
-        message = String.format("%s is not a valid host group", group);
-      }
-    } else {
-      message = String.format("%s is not a valid hostname", hostName);
-    }
-    return message;
-  }
-
-  /**
-   * Checks whether the cluster auto command is available or not.
-   *
-   * @return true if available false otherwise
-   */
-  @CliAvailabilityIndicator(value = "cluster autoAssign")
-  public boolean isClusterAutoAssignAvailable() {
-    return context.isFocusOnClusterBuild() && !isHostAssigned();
-  }
-
-  /**
-   * Tries to auto associate hosts to host groups.
-   *
-   * @return prints the auto assignments
-   */
-  @CliCommand(value = "cluster autoAssign", help = "Automatically assigns hosts to different host groups base on the provided strategy")
-  public String autoAssign() {
-    Map<String, List<String>> assignments = client.recommendAssignments(context.getFocusValue());
-    if (!assignments.isEmpty()) {
-      hostGroups = assignments;
-      context.setHint(Hints.CREATE_CLUSTER);
-    }
-    return showAssignments();
-  }
-
-  /**
-   * Checks whether the cluster preview command is available or not.
-   *
-   * @return true if available false otherwise
-   */
-  @CliAvailabilityIndicator("cluster preview")
-  public boolean isClusterPreviewCommandAvailable() {
-    return context.isFocusOnClusterBuild() && isHostAssigned();
-  }
-
-  /**
-   * Shows the currently assigned hosts.
-   *
-   * @return formatted host - host group table
-   */
-  @CliCommand(value = "cluster preview", help = "Shows the currently assigned hosts")
-  public String showAssignments() {
-    return renderMultiValueMap(hostGroups, "HOSTGROUP", "HOST");
-  }
-
-  /**
-   * Checks whether the cluster create command is available or not.
-   *
-   * @return true if available false otherwise
-   */
-  @CliAvailabilityIndicator("cluster create")
-  public boolean isCreateClusterCommandAvailable() {
-    return context.isFocusOnClusterBuild() && isHostAssigned();
-  }
-
-  /**
-   * Creates a new cluster based on the provided host - host group associations and the selected blueprint.
-   * If the cluster creation fails, deletes the cluster.
-   *
-   * @return status message
-   */
-  @CliCommand(value = "cluster create", help = "Create a cluster based on current blueprint and assigned hosts")
-  public String createCluster(
-    @CliOption(key = "exitOnFinish", mandatory = false, help = "Quits the shell when the cluster creation finishes") Boolean exit) {
-    String message = "Successfully created the cluster";
-    String blueprint = context.getFocusValue();
-    try {
-      client.createCluster(blueprint, blueprint, hostGroups);
-      context.setCluster(blueprint);
-      context.resetFocus();
-      context.setHint(Hints.PROGRESS);
-      flashService.showInstallProgress(exit == null ? false : exit);
-    } catch (HttpResponseException e) {
-      createNewHostGroups();
-      message = "Failed to create the cluster: " + e.getMessage();
-      try {
-        deleteCluster(blueprint);
-      } catch (HttpResponseException e1) {
-        message += ". Failed to cleanup cluster creation: " + e1.getMessage();
-      }
-    }
-    return message;
-  }
-
-  /**
-   * Checks whether the cluster delete command is available or not.
-   *
-   * @return true if available false otherwise
-   */
-  @CliAvailabilityIndicator("cluster delete")
-  public boolean isDeleteClusterCommandAvailable() {
-    return context.isConnectedToCluster();
-  }
-
-  /**
-   * Deletes the cluster.
-   *
-   * @return status message
-   */
-  @CliCommand(value = "cluster delete", help = "Delete the cluster")
-  public String deleteCluster() {
-    String message = "Successfully deleted the cluster";
-    try {
-      deleteCluster(context.getCluster());
-    } catch (HttpResponseException e) {
-      message = "Could not delete the cluster: " + e.getMessage();
-    }
-    return message;
-  }
-
-  /**
-   * Checks whether the cluster reset command is available or not.
-   *
-   * @return true if available false otherwise
-   */
-  @CliAvailabilityIndicator(value = "cluster reset")
-  public boolean isClusterResetCommandAvailable() {
-    return context.isFocusOnClusterBuild() && isHostAssigned();
-  }
-
-  @CliCommand(value = "cluster reset", help = "Clears the host - host group assignments")
-  public void reset() {
-    context.setHint(Hints.ASSIGN_HOSTS);
-    createNewHostGroups();
-  }
-
-  private void deleteCluster(String id) throws HttpResponseException {
-    client.deleteCluster(id);
-  }
-
-  private void createNewHostGroups() {
-    Map<String, List<String>> groups = new HashMap<String, List<String>>();
-    for (String hostGroup : client.getHostGroups(context.getFocusValue())) {
-      groups.put(hostGroup, new ArrayList<String>());
-    }
-    this.hostGroups = groups;
-  }
-
-  private boolean addHostToGroup(String host, String group) {
-    boolean result = true;
-    List<String> hosts = hostGroups.get(group);
-    if (hosts == null) {
-      result = false;
-    } else {
-      hosts.add(host);
-    }
-    return result;
-  }
-
-  private boolean isHostAssigned() {
-    boolean result = false;
-    for (String group : hostGroups.keySet()) {
-      if (!hostGroups.get(group).isEmpty()) {
-        result = true;
-        break;
-      }
-    }
-    return result;
-  }
-}

http://git-wip-us.apache.org/repos/asf/ambari/blob/c8eceafc/ambari-shell/src/main/java/org/apache/ambari/shell/commands/ElephantCommand.java
----------------------------------------------------------------------
diff --git a/ambari-shell/src/main/java/org/apache/ambari/shell/commands/ElephantCommand.java b/ambari-shell/src/main/java/org/apache/ambari/shell/commands/ElephantCommand.java
deleted file mode 100644
index a236054..0000000
--- a/ambari-shell/src/main/java/org/apache/ambari/shell/commands/ElephantCommand.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.ambari.shell.commands;
-
-import java.io.IOException;
-
-import org.apache.commons.io.IOUtils;
-import org.springframework.shell.core.CommandMarker;
-import org.springframework.shell.core.annotation.CliAvailabilityIndicator;
-import org.springframework.shell.core.annotation.CliCommand;
-import org.springframework.stereotype.Component;
-
-/**
- * Draws an elephant to the console.
- */
-@Component
-public class ElephantCommand implements CommandMarker {
-
-  /**
-   * Checks whether the hello command is available or not.
-   *
-   * @return true if available false otherwise
-   */
-  @CliAvailabilityIndicator("hello")
-  public boolean isCommandAvailable() {
-    return true;
-  }
-
-  /**
-   * Prints an elephant to the console.
-   *
-   * @return elephant
-   */
-  @CliCommand(value = "hello", help = "Prints a simple elephant to the console")
-  public String elephant() throws IOException {
-    return IOUtils.toString(getClass().getResourceAsStream("/elephant.txt"));
-  }
-}
\ No newline at end of file


[3/4] AMBARI-6176. Integrate python shell into Ambari-shell module(subin)

Posted by su...@apache.org.
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 &gt;= 2.6</python.ver>
+    <deb.python.ver>python (&gt;= 2.6)</deb.python.ver>
+    <deb.architecture>amd64</deb.architecture>
+    <deb.dependency.list>openssl, zlibc, ${deb.python.ver}</deb.dependency.list>
+  </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.