# Copyright 2014 LinkedIn Corp.
#
# 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 tarfile
import time
import zipfile
import urllib

from subprocess import call

import zopkio.constants as constants
from zopkio.deployer import Deployer, Process
from zopkio.remote_host_helper import better_exec_command, DeploymentError, get_sftp_client, get_ssh_client,\
  open_remote_file, log_output, exec_with_env
import zopkio.runtime as runtime

logger = logging.getLogger(__name__)

class SSHDeployer(Deployer):
  """
  A simple deployer that copies an executable to the remote host and runs it
  """

  def __init__(self, service_name, configs=None):
    """
    Creates a new SSHDeployer, typical use case is to create one deployer per service. The functions of the
    deployer are driven by configs. The configs can be set in the constructor as defaults and subsequently overridden
    during each invocation. The following configs are currently supported
      additional_directories: used during uninstall to remove additional directories see directories_to_clean
      args: used during start to give args to the start command
      delay: used during start or stop to add a delay before returning in order to allow the service time to start up
      directories_to_clean: used during uninstall to removed additional directories
      env: used during install/start/stop/get_pid to run custom commands with the specified environment
      executable: the executable that defines this service
      extract: used during install to now if the executable should be extracted
      hostname: used during each function to specify the host to execute it on,
       should be passed per call rather than set by default
      install_path: the path to install the executable
      no_copy: used during install to skip the installation step if the executable has already been copied
      pid_command: used during get_pid if this is specified than the command will be used to determine the pid of the executable
        use this or pid_file or pid_keyword
      pid_file: used during get_pid if this is specified than the file will be read to determine the pid of the executable
        use this or pid_command or pid_keyword
      pid_keyword: used during get_pid if this is specified than the keyword will be used with pgrep to determine the pid of the executable
        use this or pid_command or pid_file
      post_install_cmds: used during install to run custom commands prior to running start
      start_command: used during start, the command to start the service
      stop_command: used during stop, the command to stop the service
      sync: used during start, whether the start command is synchronous or not (Default not)
      terminate_only: used during stop to terminate the process rather than using the stop command
    :param service_name: an arbitrary name that can be used to describe the executable
    :param configs: default configurations for the other methods
    :return:
    """
    logging.getLogger("paramiko").setLevel(logging.ERROR)
    self.service_name = service_name
    self.default_configs = {} if configs is None else configs
    Deployer.__init__(self)

  def install(self, unique_id, configs=None):
    """
    Copies the executable to the remote machine under install path. Inspects the configs for the possible keys