Source code for Exscript.host

#
# Copyright (C) 2010-2017 Samuel Abels
# The MIT License (MIT)
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"""
Representing a device to connect with.
"""
from __future__ import absolute_import
from builtins import str
from builtins import object
from .account import Account
from .util.cast import to_list
from .util.ipv4 import is_ip, clean_ip
from .util.url import Url


def _is_ip(string):
    # Adds IPv6 support.
    return ':' in string or is_ip(string)


[docs]class Host(object): """ Represents a device on which to open a connection. """ __slots__ = ('protocol', 'vars', 'account', 'name', 'address', 'tcp_port', 'options')
[docs] def __init__(self, uri, default_protocol='telnet'): """ Constructor. The given uri is passed to Host.set_uri(). The default_protocol argument defines the protocol that is used in case the given uri does not specify it. :type uri: string :param uri: A hostname; see set_uri() for more info. :type default_protocol: string :param default_protocol: The protocol name. """ self.protocol = default_protocol self.vars = None # To save memory, do not init with a dict. self.account = None self.name = None self.address = None self.tcp_port = None self.options = None self.set_uri(uri)
def __copy__(self): host = Host(self.get_uri()) host.set_name(self.get_name()) return host
[docs] def set_uri(self, uri): """ Defines the protocol, hostname/address, TCP port number, username, and password from the given URL. The hostname may be URL formatted, so the following formats are all valid: - myhostname - myhostname.domain - ssh:hostname - ssh:hostname.domain - ssh://hostname - ssh://user@hostname - ssh://user:password@hostname - ssh://user:password@hostname:21 For a list of supported protocols please see set_protocol(). :type uri: string :param uri: An URL formatted hostname. """ try: uri = Url.from_string(uri, self.protocol) except ValueError: raise ValueError('Hostname parse error: ' + repr(uri)) hostname = uri.hostname or '' name = uri.path and hostname + uri.path or hostname self.set_protocol(uri.protocol) self.set_tcp_port(uri.port) self.set_name(name) self.set_address(name) if uri.username is not None \ or uri.password1 is not None \ or uri.password2: account = Account(uri.username, uri.password1, uri.password2) self.set_account(account) for key, val in list(uri.vars.items()): self.set(key, val)
[docs] def get_uri(self): """ Returns a URI formatted representation of the host, including all of it's attributes except for the name. Uses the address, not the name of the host to build the URI. :rtype: str :return: A URI. """ url = Url() url.protocol = self.get_protocol() url.hostname = self.get_address() url.port = self.get_tcp_port() url.vars = dict((k, to_list(v)) for (k, v) in list(self.get_all().items()) if isinstance(v, str) or isinstance(v, list)) if self.account: url.username = self.account.get_name() url.password1 = self.account.get_password() url.password2 = self.account.authorization_password return str(url)
[docs] def get_dict(self): """ Returns a dict containing the host's attributes. The following keys are contained: - hostname - address - protocol - port :rtype: dict :return: The resulting dictionary. """ return {'hostname': self.get_name(), 'address': self.get_address(), 'protocol': self.get_protocol(), 'port': self.get_tcp_port()}
[docs] def set_name(self, name): """ Set the hostname of the remote host without changing username, password, protocol, and TCP port number. :type name: string :param name: A hostname or IP address. """ self.name = name
[docs] def get_name(self): """ Returns the name. :rtype: string :return: The hostname excluding the name. """ return self.name
[docs] def set_address(self, address): """ Set the address of the remote host the is contacted, without changing hostname, username, password, protocol, and TCP port number. This is the actual address that is used to open the connection. :type address: string :param address: A hostname or IP name. """ if is_ip(address): self.address = clean_ip(address) else: self.address = address
[docs] def get_address(self): """ Returns the address that is used to open the connection. :rtype: string :return: The address that is used to open the connection. """ return self.address
[docs] def set_protocol(self, protocol): """ Defines the protocol. The following protocols are currently supported: - telnet: Telnet - ssh1: SSH version 1 - ssh2: SSH version 2 - ssh: Automatically selects the best supported SSH version - dummy: A virtual device that accepts any command, but that does not respond anything useful. - pseudo: A virtual device that loads a file with the given "hostname". The given file is a Python file containing information on how the virtual device shall respond to commands. For more information please refer to the documentation of protocols.Dummy.load_command_handler_from_file(). :type protocol: string :param protocol: The protocol name. """ self.protocol = protocol
[docs] def get_protocol(self): """ Returns the name of the protocol. :rtype: string :return: The protocol name. """ return self.protocol
[docs] def set_option(self, name, value): """ Defines a (possibly protocol-specific) option for the host. Possible options include: verify_fingerprint: bool :type name: str :param name: The option name. :type value: object :param value: The option value. """ if name not in ('debug', 'verify_fingerprint', 'driver'): raise TypeError('No such option: ' + repr(name)) if self.options is None: self.options = {} self.options[name] = value
[docs] def get_option(self, name, default=None): """ Returns the value of the given option if it is defined, returns the given default value otherwise. :type name: str :param name: The option name. :type default: object :param default: A default value. """ if self.options is None: return default return self.options.get(name, default)
[docs] def get_options(self): """ Return a dictionary containing all defined options. :rtype: dict :return: The options. """ if self.options is None: return {} return self.options
[docs] def set_tcp_port(self, tcp_port): """ Defines the TCP port number. :type tcp_port: int :param tcp_port: The TCP port number. """ if tcp_port is None: self.tcp_port = None return self.tcp_port = int(tcp_port)
[docs] def get_tcp_port(self): """ Returns the TCP port number. :rtype: string :return: The TCP port number. """ return self.tcp_port
[docs] def set_account(self, account): """ Defines the account that is used to log in. :type account: :class:`Exscript.Account` :param account: The account. """ self.account = account
[docs] def get_account(self): """ Returns the account that is used to log in. :rtype: Account :return: The account. """ return self.account
[docs] def set(self, name, value): """ Stores the given variable/value in the object for later retrieval. :type name: string :param name: The name of the variable. :type value: object :param value: The value of the variable. """ if self.vars is None: self.vars = {} self.vars[name] = value
[docs] def set_all(self, variables): """ Like set(), but replaces all variables by using the given dictionary. In other words, passing an empty dictionary results in all variables being removed. :type variables: dict :param variables: The dictionary with the variables. """ self.vars = dict(variables)
[docs] def append(self, name, value): """ Appends the given value to the list variable with the given name. :type name: string :param name: The name of the variable. :type value: object :param value: The appended value. """ if self.vars is None: self.vars = {} if name in self.vars: self.vars[name].append(value) else: self.vars[name] = [value]
[docs] def set_default(self, name, value): """ Like set(), but only sets the value if the variable is not already defined. :type name: string :param name: The name of the variable. :type value: object :param value: The value of the variable. """ if self.vars is None: self.vars = {} if name not in self.vars: self.vars[name] = value
[docs] def has_key(self, name): """ Returns True if the variable with the given name is defined, False otherwise. :type name: string :param name: The name of the variable. :rtype: bool :return: Whether the variable is defined. """ if self.vars is None: return False return name in self.vars
[docs] def get(self, name, default=None): """ Returns the value of the given variable, or the given default value if the variable is not defined. :type name: string :param name: The name of the variable. :type default: object :param default: The default value. :rtype: object :return: The value of the variable. """ if self.vars is None: return default return self.vars.get(name, default)
[docs] def get_all(self): """ Returns a dictionary containing all variables. :rtype: dict :return: The dictionary with the variables. """ if self.vars is None: self.vars = {} return self.vars