Source code for networkapi.plugins.base

# -*- coding: utf-8 -*-
# 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 random
import re
import string
import unicodedata
from time import sleep

import paramiko

from . import exceptions
from networkapi.api_rest import exceptions as api_exceptions
from networkapi.equipamento.models import EquipamentoAcesso
from networkapi.settings import TFTP_SERVER_ADDR
from networkapi.util.decorators import mock_return


log = logging.getLogger(__name__)


[docs]class BasePlugin(object): """Base plugin interface.""" ERROR_REGEX = '[Ee][Rr][Rr][Oo][Rr]|[Ff]ail|\%|utility is occupied' INVALID_REGEX = '([Ii]nvalid)' VALID_TFTP_GET_MESSAGE = 'Copy complete, now saving to disk' VALID_TFTP_PUT_MESSAGE = 'bytes copied in' VALID_OUTPUT_CHARS = '-_.():/#\\\r\n %s%s' % (string.ascii_letters, string.digits) admin_privileges = 'not defined' GUEST_PRIVILEGES = 'not defined' connect_port = 22 connect_max_retries = 3 equipment = None equipment_access = None channel = None remote_conn = None tftpserver = TFTP_SERVER_ADDR management_vrf = '' def __init__(self, **kwargs): if 'equipment' in kwargs: self.equipment = kwargs.get('equipment') if 'equipment_access' in kwargs: self.equipment_access = kwargs.get('equipment_access') if 'connect_port' in kwargs: self.connect_port = kwargs.get('connect_port') if 'tftpserver' in kwargs: self.tftpserver = kwargs.get('tftpserver')
[docs] def copyScriptFileToConfig(self, filename, use_vrf='', destination=''): """Copy file from server to destination configuration. By default, plugin should apply file in running configuration (active). """ raise NotImplementedError()
[docs] @mock_return('') def connect(self): """Connects to equipment via ssh using paramiko.SSHClient and sets channel variable with invoked shell object. Raises: IOError: if cannot connect to host Exception: for other unhandled exceptions """ if self.equipment_access is None: try: self.equipment_access = EquipamentoAcesso.search( None, self.equipment, 'ssh').uniqueResult() except Exception: log.error('Access type %s not found for equipment %s.' % ('ssh', self.equipment.nome)) raise exceptions.InvalidEquipmentAccessException() device = self.equipment_access.fqdn username = self.equipment_access.user password = self.equipment_access.password self.remote_conn = paramiko.SSHClient() self.remote_conn.set_missing_host_key_policy(paramiko.AutoAddPolicy()) try: retries = 0 connected = 0 while(not connected and retries < self.connect_max_retries): try: self.remote_conn.connect( device, port=self.connect_port, username=username, password=password) self.channel = self.remote_conn.invoke_shell() connected = 1 except Exception, e: retries += 1 # not capable of connecting after max retries if retries is self.connect_max_retries: raise Exception(e) log.error('Try %s/%s - Error connecting to host %s: %s' % (retries, self.connect_max_retries, device, e)) sleep(random.randint(1, 15)) except IOError, e: log.error('Could not connect to host %s: %s' % (device, e)) raise exceptions.ConnectionException(device) except Exception, e: log.error('Error connecting to host %s: %s' % (device, e)) raise Exception(e)
[docs] def create_svi(self, svi_number, svi_description='no description'): """Delete SVI in switch.""" raise NotImplementedError()
[docs] @mock_return('') def close(self): self.channel.close()
[docs] def ensure_privilege_level(self, privilege_level=None): """Ensure connection has the right privileges expected.""" raise NotImplementedError()
[docs] @mock_return('') def exec_command(self, command, success_regex='', invalid_regex=None, error_regex=None): """Send single command to equipment and than closes connection channel. """ if self.channel is None: log.error( 'No channel connection to the equipment %s. Was the connect() funcion ever called?' % self.equipment.nome) raise exceptions.PluginNotConnected() try: stdin, stdout, stderr = self.channel.exec_command('%s' % (command)) except Exception, e: log.error('Error in connection. Cannot send command %s: %s' % (command, e)) raise api_exceptions.NetworkAPIException equip_output_lines = stdout.readlines() output_text = ''.join(equip_output_lines) if re.search(invalid_regex, output_text, re.DOTALL): raise exceptions.InvalidCommandException(output_text) elif re.search(error_regex, output_text, re.DOTALL): raise exceptions.CommandErrorException elif re.search(success_regex, output_text, re.DOTALL): return output_text else: raise exceptions.UnableToVerifyResponse()
[docs] def removeDisallowedChars(self, data): data = u'%s' % data cleanedstr = unicodedata.normalize( 'NFKD', data).encode('ASCII', 'ignore') return ''.join(c for c in cleanedstr if c in self.VALID_OUTPUT_CHARS)
[docs] def remove_svi(self, svi_number): """Delete SVI from switch.""" raise NotImplementedError()
[docs] def waitString(self, wait_str_ok_regex='', wait_str_invalid_regex=None, wait_str_failed_regex=None): if wait_str_invalid_regex is None: wait_str_invalid_regex = self.INVALID_REGEX if wait_str_failed_regex is None: wait_str_failed_regex = self.ERROR_REGEX string_ok = 0 recv_string = '' while not string_ok: while not self.channel.recv_ready(): sleep(1) recv_string = self.channel.recv(9999) file_name_string = self.removeDisallowedChars(recv_string) if re.search(wait_str_invalid_regex, recv_string, re.DOTALL): raise exceptions.CommandErrorException(file_name_string) elif re.search(wait_str_failed_regex, recv_string, re.DOTALL): raise exceptions.InvalidCommandException(file_name_string) elif re.search(wait_str_ok_regex, recv_string, re.DOTALL): string_ok = 1 return recv_string
[docs] def get_state_member(self, status): """Return state of poolmember.""" raise NotImplementedError()
[docs] def set_state_member(self, status): """Set state of poolmember.""" raise NotImplementedError()
[docs] def create_member(self, status): """Crate poolmember.""" raise NotImplementedError()
[docs] def remove_member(self, status): """Remove poolmember.""" raise NotImplementedError()
[docs] def get_restrictions(self, status): """Remove poolmember.""" raise NotImplementedError()
[docs] def partial_update_vip(self, **kwargs): """ Partial Update of VIP.""" raise NotImplementedError()
[docs] def get_name_eqpt(self, **kwargs): """Generate name of VIP.""" raise NotImplementedError()
[docs] def update_pool(self, **kwargs): """Update of VIP.""" raise NotImplementedError()
[docs] def create_pool(self, **kwargs): """Create of VIP.""" raise NotImplementedError()
[docs] def delete_pool(self, **kwargs): """Delete of VIP.""" raise NotImplementedError()