pax_global_header00006660000000000000000000000064132567367410014530gustar00rootroot0000000000000052 comment=b283b70f5685fda56aff1ef1516c33cbbd8ad839 nova-agent-2.1.13/000077500000000000000000000000001325673674100136535ustar00rootroot00000000000000nova-agent-2.1.13/.gitignore000066400000000000000000000001051325673674100156370ustar00rootroot00000000000000__pycache__ *.pyc *.swp /build /dist /*.egg-info .coverage .DS_Store nova-agent-2.1.13/.travis.yml000066400000000000000000000003361325673674100157660ustar00rootroot00000000000000 language: python python: - "2.6" - "2.7" - "3.4" - "3.5" - "3.6" install: - pip install -e .[tests] before_script: - flake8 . script: - nosetests -v --cover-erase --with-coverage --cover-package=novaagent nova-agent-2.1.13/LICENSE000066400000000000000000000010541325673674100146600ustar00rootroot00000000000000Copyright 2017 Rackspace, Inc. 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. nova-agent-2.1.13/MANIFEST.in000066400000000000000000000000661325673674100154130ustar00rootroot00000000000000graft etc graft debian graft pkgs include LICENSE.txt nova-agent-2.1.13/README.md000066400000000000000000000002461325673674100151340ustar00rootroot00000000000000 [![Travis Status](https://travis-ci.org/Rackspace-DOT/nova-agent.svg?branch=master)](https://travis-ci.org/Rackspace-DOT/nova-agent.svg?branch=master) # nova agent nova-agent-2.1.13/etc/000077500000000000000000000000001325673674100144265ustar00rootroot00000000000000nova-agent-2.1.13/etc/nova-agent.init000066400000000000000000000024121325673674100173510ustar00rootroot00000000000000#!/bin/sh # LSB style init header: # ### BEGIN INIT INFO # Provides: Nova-Agent # Required-Start: $remote_fs $syslog xe-linux-distribution # Required-Stop: $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Start nova-agent at boot time # Description: nova-agent is a guest agent for OpenStack nova. ### END INIT INFO # Source function library. . /lib/lsb/init-functions PROG=nova-agent exec=/usr/bin/$PROG pid_file=/var/run/nova-agent.pid LOCK=/var/lock/subsys/$PROG do_start() { if pidofproc -p $pid_file; then return 0 fi start-stop-daemon --background --make-pidfile --pidfile $pid_file --start --exec $exec -- -o /var/log/nova-agent.log -l info --no-fork true RETVAL=$? echo "Starting $PROG... " if [ $RETVAL -eq 0 ]; then [ -d /var/lock/subsys ] || mkdir -p /var/lock/subsys touch $LOCK fi return $RETVAL } do_stop() { start-stop-daemon --pidfile $pid_file --stop RETVAL=$? echo "Stopping $PROG... " if [ $RETVAL -eq 0 ]; then rm -f $LOCK fi return $RETVAL } case "$1" in start) do_start ;; stop) do_stop ;; restart) do_stop do_start ;; *) echo "Usage: $SCRIPTNAME {start|stop|restart}" >&2 exit 3 ;; esac nova-agent-2.1.13/etc/nova-agent.redhat000066400000000000000000000034111325673674100176550ustar00rootroot00000000000000#!/bin/sh # # nova-agent Agent for setting up clean servers on Xen # # chkconfig: 2345 15 85 # description: Starts and stops the nova-agent daemon. ### BEGIN INIT INFO # Provides: nova-agent # Required-Start: $all # Required-Stop: # Should-Start: # Should-Stop: # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: nova-agent daemon # Description: Starts and stops the nova-agent daemon. ### END INIT INFO # Source function library. . /etc/rc.d/init.d/functions prog="nova-agent" exec="/usr/bin/$prog" pidfile="/var/run/nova-agent.pid" lockfile="/var/lock/subsys/$prog" logfile="/var/log/nova-agent.log" loglevel="info" start() { [ -x $exec ] || exit 5 echo -n $"Starting $prog: " daemon $exec -o $logfile -l $loglevel retval=$? echo [ $retval -eq 0 ] && touch $lockfile return $retval } stop() { echo -n $"Stopping $prog: " killproc $prog retval=$? echo [ $retval -eq 0 ] && rm -f $lockfile return $retval } restart() { stop start } reload() { restart } force_reload() { restart } rh_status() { status $prog } rh_status_q() { rh_status >/dev/null 2>&1 } case "$1" in start) rh_status_q && exit 0 $1 ;; stop) rh_status_q || exit 0 $1 ;; restart) $1 ;; reload) rh_status_q || exit 7 $1 ;; force-reload) force_reload ;; status) rh_status ;; condrestart|try-restart) rh_status_q || exit 0 restart ;; *) echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}" exit 2 ;; esac exit $? # https://fedoraproject.org/wiki/EPEL:SysVInitScript nova-agent-2.1.13/etc/nova-agent.service000066400000000000000000000002731325673674100200510ustar00rootroot00000000000000[Unit] Description=Nova Agent for xenstore Before=network.target [Service] Type=forking ExecStart=/usr/bin/nova-agent -o /var/log/nova-agent.log -l info [Install] WantedBy=basic.target nova-agent-2.1.13/etc/nova-agent.upstart000066400000000000000000000003601325673674100201100ustar00rootroot00000000000000description "Nova Agent upstart script" author "Rackspace" start on networking or runlevel [2345] stop on runlevel [!2345] respawn respawn limit 10 5 expect fork umask 022 exec /usr/bin/nova-agent -o /var/log/nova-agent.log -l info nova-agent-2.1.13/novaagent/000077500000000000000000000000001325673674100156355ustar00rootroot00000000000000nova-agent-2.1.13/novaagent/__init__.py000066400000000000000000000000301325673674100177370ustar00rootroot00000000000000 __version__ = '2.1.13' nova-agent-2.1.13/novaagent/common/000077500000000000000000000000001325673674100171255ustar00rootroot00000000000000nova-agent-2.1.13/novaagent/common/__init__.py000066400000000000000000000000001325673674100212240ustar00rootroot00000000000000nova-agent-2.1.13/novaagent/common/file_inject.py000066400000000000000000000062111325673674100217520ustar00rootroot00000000000000# Copyright (c) 2011 Openstack, LLC. # All Rights Reserved. # # 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. # """ JSON File injection plugin """ from __future__ import print_function from novaagent.utils import encode_to_bytes from novaagent.utils import backup_file from tempfile import mkstemp import base64 import stat import os # This needs to be looked at def _get_file_permissions(filename): try: _stat = os.stat(filename) return (_stat.st_mode, _stat.st_uid, _stat.st_gid) except Exception: """ Catching base exception as Python 2.x does not have FileNotFoundError exception as python 3.X """ return (None, 0, 0) def _write_file(filename, data): # Get permissions from existing file if it exists permission, owner, group = _get_file_permissions(filename) dirname = os.path.dirname(filename) if not os.path.exists(dirname): os.makedirs(dirname) """ Create temporary file in the directory we want to place the file into https://docs.python.org/2/library/tempfile.html From the documentation: There are no race conditions in the file's creation, assuming that the platform properly implements the os.O_EXCL flag for os.open(). The file is readable and writable only by the creating user ID. """ fd, temp_path = mkstemp(dir=dirname, text=True) try: """ Set the ownership for the file. If it fails owner/group will be root as that is what nova-agent runs under """ os.fchown(fd, owner, group) except Exception: pass try: os.fchmod(fd, permission) except Exception: # If existing file is not found, then set permissions to default 600 os.fchmod(fd, stat.S_IRUSR | stat.S_IWUSR) # Write data to file after all the permissions are set on the temp file try: os.write(fd, data) except TypeError: # Python 3 expects bytes so convert and then write to file os.write(fd, encode_to_bytes(data)) os.close(fd) # Check for existence of file and back the original up if os.path.exists(filename): backup_file(filename) # Rename the temp file and put in place os.rename(temp_path, filename) class FileInject(object): def __init__(self, *args, **kwargs): pass def injectfile_cmd(self, data): try: b64_decoded = base64.b64decode(data) except Exception: return ("500", "Error doing base64 decoding of data") filename, data = b64_decoded.decode('utf-8').split(',', 1) _write_file(filename, data) return ("0", "") nova-agent-2.1.13/novaagent/common/kms.py000066400000000000000000000075021325673674100202750ustar00rootroot00000000000000# # Copyright (c) 2011 Openstack, LLC. # All Rights Reserved. # # 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. # """ redhat/centos KMS activation helper module """ from __future__ import print_function import subprocess import logging import os RHN_PATH = '/etc/sysconfig/rhn' SYSTEMID_PATH = os.path.join(RHN_PATH, 'systemid') UP2DATE_PATH = os.path.join(RHN_PATH, 'up2date') def register_with_rhn(activation_key, profile): if os.path.exists(SYSTEMID_PATH): os.unlink(SYSTEMID_PATH) # Call rhnreg_ks logging.debug( 'executing /usr/sbin/rhnreg_ks --activationkey ' ' --profile %s --force' % profile ) pipe = subprocess.PIPE p = subprocess.Popen( [ '/usr/sbin/rhnreg_ks', '--activationkey', activation_key, '--profile', profile, '--force' ], stdin=pipe, stdout=pipe, stderr=pipe, env={} ) logging.debug('waiting on pid %d' % p.pid) status = os.waitpid(p.pid, 0)[1] logging.debug('status = %d' % status) if status != 0: return ("500", "Couldn't activate with RHN: %d" % status) def configure_up2date(domains): if not isinstance(domains, list): domains = [domains] domains = ['//%s/XMLRPC' % d for d in domains] serverURL = ';'.join(['https:%s' % h for h in domains]) noSSLServerURL = ';'.join(['http:%s' % h for h in domains]) data = """ # Automatically generated Red Hat Update Agent config file, do not edit. # Format: 1.0 versionOverride[comment]=Override the automatically determined system version versionOverride= enableProxyAuth[comment]=To use an authenticated proxy or not enableProxyAuth=0 networkRetries[comment]=Number of attempts to make at network """ \ """connections before giving up networkRetries=5 hostedWhitelist[comment]=None hostedWhitelist= enableProxy[comment]=Use a HTTP Proxy enableProxy=0 serverURL[comment]=Remote server URL serverURL=%(serverURL)s; proxyPassword[comment]=The password to use for an authenticated proxy proxyPassword= noSSLServerURL[comment]=None noSSLServerURL=%(noSSLServerURL)s; proxyUser[comment]=The username for an authenticated proxy proxyUser= disallowConfChanges[comment]=Config options that can not be """ \ """overwritten by a config update action disallowConfChanges=noReboot;sslCACert;useNoSSLForPackages;""" \ """noSSLServerURL;serverURL;disallowConfChanges; sslCACert[comment]=The CA cert used to verify the ssl server sslCACert=/usr/share/rhn/RHN-ORG-TRUSTED-SSL-CERT debug[comment]=Whether or not debugging is enabled debug=0 httpProxy[comment]=HTTP proxy in host:port format, e.g. squid.redhat.com:3128 httpProxy= systemIdPath[comment]=Location of system id systemIdPath=/etc/sysconfig/rhn/systemid noReboot[comment]=Disable the reboot action noReboot=0 """ % {'serverURL': serverURL, 'noSSLServerURL': noSSLServerURL} return {UP2DATE_PATH: data} def kms_activate(data): activation_key = data['activation_key'] profile = data['profile'] domains = data['domains'] update_files = configure_up2date(domains) with open(UP2DATE_PATH, 'w') as up2date: print(update_files[UP2DATE_PATH], file=up2date) message = register_with_rhn(activation_key, profile) if message: return message return ("0", "") nova-agent-2.1.13/novaagent/common/password.py000066400000000000000000000140071325673674100213430ustar00rootroot00000000000000# # Copyright (c) 2011 Openstack, LLC. # All Rights Reserved. # # 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. # """ JSON password reset handling plugin """ from subprocess import PIPE from subprocess import Popen import binascii import base64 import sys import os from Crypto.Cipher import AES if sys.version_info > (3,): long = int # This is to support older python versions that don't have hashlib try: import hashlib except ImportError as exc: import md5 class hashlib(object): """Fake hashlib module as a class""" @staticmethod def md5(): return md5.new() class PasswordError(Exception): """ Class for password command exceptions """ def __init__(self, response): # Should be a (ResponseCode, ResponseMessage) tuple self.response = response def __str__(self): return "%s: %s" % self.response def get_response(self): return self.response class PasswordCommands(object): """ Class for password related commands """ def __init__(self): self.prime = 162259276829213363391578010288127 self.base = 5 self.min_key_length = 540 self._public = None self._private = None self._shared = None self._aes_key = None self._aes_iv = None def _generate_private_key(self): """Create a private key using /dev/urandom""" _bytes = self.min_key_length // 8 + 8 self._private = int(binascii.hexlify(os.urandom(_bytes)), 16) def _compute_public_key(self): """Given a private key, compute a public key""" self._public = pow(self.base, self._private, self.prime) def _compute_shared_key(self, remote_public_key): """Given public and private keys, compute the shared key""" self._shared = pow(remote_public_key, self._private, self.prime) def _compute_aes_key(self): """ Given a key, compute the corresponding key that can be used with AES """ shared_string = str(self._shared) self._aes_key = (hashlib.md5(shared_string.encode('utf-8'))).digest() m = hashlib.md5(self._aes_key) m.update(shared_string.encode('utf-8')) self._aes_iv = m.digest() def _decrypt_password(self, data): aes = AES.new(self._aes_key, AES.MODE_CBC, self._aes_iv) decrypted_passwd = aes.decrypt(data) try: cut_off_sz = ord(decrypted_passwd[len(decrypted_passwd) - 1]) except Exception: cut_off_sz = decrypted_passwd[len(decrypted_passwd) - 1] if cut_off_sz > 16 or len(decrypted_passwd) < 16: raise PasswordError((500, "Invalid password data received")) passwd = decrypted_passwd[: - cut_off_sz] return passwd def _decode_password(self, data): try: real_data = base64.b64decode(data) except Exception as exc: raise PasswordError((500, "Couldn't decode base64 data")) if self._aes_key is None: raise PasswordError((500, "Password without key exchange")) try: passwd = self._decrypt_password(real_data) except PasswordError as exc: raise exc except Exception as exc: raise PasswordError((500, str(exc))) return passwd def _change_password(self, passwd): if isinstance(passwd, bytes): string_passwd = passwd.decode('utf-8') else: string_passwd = str(passwd) # Make sure there are no newlines at the end set_password('root', string_passwd.strip('\n')) def _wipe_keys(self): """ Reset Values from previous keyinit command as each password keyinit is called again and new values are generated """ self._aes_key = None self._aes_iv = None self._private = None self._public = None self._shared = None def keyinit_cmd(self, data): """ Remote public key should come in as a large number. Set it to long in case it comes in as a string """ remote_public_key = long(data) # Sets self._private self._generate_private_key() # Sets self._public self._compute_public_key() # Sets self._shared self._compute_shared_key(remote_public_key) # Sets self._aes_key and self._aes_iv self._compute_aes_key() # Return the public key as a string return ("D0", str(self._public)) def password_cmd(self, data): try: passwd = self._decode_password(data) self._change_password(passwd) except PasswordError as exc: return exc.get_response() self._wipe_keys() return ("0", "") def set_password(user, password): """Set the password for a particular user using passwd""" p = Popen( ['passwd', user], stdout=PIPE, stderr=PIPE, stdin=PIPE ) try: p.stdin.write(u'{0}\n{0}\n'.format(password)) except TypeError: # Python 3 wants bytes so catch the exception and encode properly p.stdin.write(u'{0}\n{0}\n'.format(password).encode('utf-8')) p.stdin.flush() out, err = p.communicate() if p.returncode != 0: raise PasswordError( ( 500, 'Failed to change password for {0}: {1} : {2}'.format( user, p.returncode, err ) ) ) return nova-agent-2.1.13/novaagent/libs/000077500000000000000000000000001325673674100165665ustar00rootroot00000000000000nova-agent-2.1.13/novaagent/libs/__init__.py000066400000000000000000000017051325673674100207020ustar00rootroot00000000000000 from __future__ import absolute_import import novaagent from novaagent.common.password import PasswordCommands from novaagent.common.file_inject import FileInject class DefaultOS(object): def keyinit(self, name, value, client): if not hasattr(self, 'p'): self.p = PasswordCommands() return self.p.keyinit_cmd(value) def password(self, name, value, client): if not hasattr(self, 'p'): self.p = PasswordCommands() return self.p.password_cmd(value) def injectfile(self, name, value, client): if not hasattr(self, 'f'): self.f = FileInject() return self.f.injectfile_cmd(value) def features(self, name, value, client): return ( '0', 'kmsactivate,resetnetwork,version,keyinit,' 'features,password,injectfile' ) def version(self, name, value, client): return ('0', str(novaagent.__version__)) nova-agent-2.1.13/novaagent/libs/centos.py000066400000000000000000000171261325673674100204420ustar00rootroot00000000000000 from __future__ import print_function from __future__ import absolute_import import logging import os from subprocess import Popen from subprocess import PIPE from novaagent import utils from novaagent.libs import DefaultOS log = logging.getLogger(__name__) class ServerOS(DefaultOS): def __init__(self): self.netconfig_dir = '/etc/sysconfig/network-scripts' self.interface_file_prefix = 'ifcfg' self.route_file_prefix = 'route' self.hostname_file = '/etc/hostname' self.network_file = '/etc/sysconfig/network' def _setup_interface(self, ifname, iface): interface_file = '{0}/{1}-{2}'.format( self.netconfig_dir, self.interface_file_prefix, ifname ) utils.backup_file(interface_file) with open(interface_file, 'w') as iffile: iffile.write('# Automatically generated, do not edit\n\n') iffile.write('# Label {0}\n'.format(iface['label'])) iffile.write('BOOTPROTO=static\n') iffile.write('DEVICE={0}\n'.format(ifname)) for count, ip_info in enumerate(iface['ips']): if count == 0: iffile.write('IPADDR={0}\n'.format(ip_info['ip'])) iffile.write('NETMASK={0}\n'.format(ip_info['netmask'])) else: iffile.write( 'IPADDR{0}={1}\n'.format( count, ip_info['ip'] ) ) iffile.write( 'NETMASK{0}={1}\n'.format( count, ip_info['netmask'] ) ) if 'gateway' in iface and iface['gateway']: iffile.write('GATEWAY={0}\n'.format(iface['gateway'])) if 'ip6s' in iface and iface['ip6s']: iffile.write('IPV6INIT=yes\n') for count, ip6_info in enumerate(iface['ip6s']): if count == 0: iffile.write( 'IPV6ADDR={0}/{1}\n'.format( ip6_info['ip'], ip6_info['netmask'] ) ) else: iffile.write( 'IPV6ADDR{0}={1}/{2}\n'.format( count, ip6_info['ip'], ip6_info['netmask'] ) ) iffile.write( 'IPV6_DEFAULTGW={0}%{1}\n'.format( iface['gateway_v6'], ifname ) ) if 'dns' in iface and iface['dns']: for count, dns in enumerate(iface['dns']): iffile.write('DNS{0}={1}\n'.format(count + 1, dns)) iffile.write('ONBOOT=yes\n') iffile.write('NM_CONTROLLED=no\n') def _setup_routes(self, ifname, iface): route_file = '{0}/{1}-{2}'.format( self.netconfig_dir, self.route_file_prefix, ifname ) utils.backup_file(route_file) with open(route_file, 'w') as routefile: for count, route in enumerate(iface['routes']): routefile.write( 'ADDRESS{0}={1}\n'.format( count, route['route'] ) ) routefile.write( 'NETMASK{0}={1}\n'.format( count, route['netmask'] ) ) routefile.write( 'GATEWAY{0}={1}\n'.format( count, route['gateway'] ) ) def _setup_hostname(self, client): hostname = utils.get_hostname(client) completed = False if os.path.exists('/usr/bin/hostnamectl'): utils.backup_file(self.hostname_file) p = Popen( ['hostnamectl', 'set-hostname', hostname], stdout=PIPE, stderr=PIPE, stdin=PIPE ) out, err = p.communicate() if p.returncode != 0: log.error('Error using hostnamectl: {0}'.format(err)) else: # Do not run hostname since it was successful completed = True if not completed: p = Popen( ['hostname', hostname], stdout=PIPE, stderr=PIPE, stdin=PIPE ) out, err = p.communicate() if p.returncode != 0: log.error('Error using hostname: {0}'.format(err)) return p.returncode, hostname def resetnetwork(self, name, value, client): ifaces = {} hostname_return_code, hostname = self._setup_hostname(client) if hostname_return_code != 0: log.error( 'Error setting hostname: {0}'.format(hostname_return_code) ) xen_macs = utils.list_xenstore_macaddrs(client) for iface in utils.list_hw_interfaces(): mac = utils.get_hw_addr(iface) if not mac or mac not in xen_macs: continue ifaces[iface] = utils.get_interface(mac, client) utils.backup_file(self.network_file) with open(self.network_file, 'w') as netfile: netfile.write('NETWORKING=yes\n') netfile.write('NOZEROCONF=yes\n') netfile.write('NETWORKING_IPV6=yes\n') netfile.write('HOSTNAME={0}\n'.format(hostname)) # move unused interface files out of the way but back them up move_files = utils.get_ifcfg_files_to_remove( self.netconfig_dir, '{0}-'.format(self.interface_file_prefix) ) for interface_config in move_files: utils.backup_file(interface_config) # setup interface files for ifname, iface in ifaces.items(): self._setup_interface(ifname, iface) if 'routes' in iface: self._setup_routes(ifname, iface) """ Creating servers from custom images may leave IP information from the image source. Flush the interface before restart of the network to clear out source image IP information """ p = Popen( ['ip', 'addr', 'flush', 'dev', ifname], stdout=PIPE, stderr=PIPE, stdin=PIPE ) out, err = p.communicate() if p.returncode != 0: # Log error and continue to restart network log.error('Error flushing interface: {0}'.format(ifname)) if os.path.exists('/usr/bin/systemctl'): p = Popen( ['systemctl', 'restart', 'network.service'], stdout=PIPE, stderr=PIPE, stdin=PIPE ) else: p = Popen( ['service', 'network', 'restart'], stdout=PIPE, stderr=PIPE, stdin=PIPE ) out, err = p.communicate() if p.returncode != 0: log.error('Error received on network restart: {0}'.format(err)) return (str(p.returncode), 'Error restarting network') return ('0', '') nova-agent-2.1.13/novaagent/libs/debian.py000066400000000000000000000260261325673674100203700ustar00rootroot00000000000000 from __future__ import print_function from __future__ import absolute_import import logging import time import yaml import os from subprocess import PIPE from subprocess import Popen from novaagent import utils from novaagent.libs import DefaultOS log = logging.getLogger(__name__) class ServerOS(DefaultOS): def __init__(self): self.netplan_file = '/etc/netplan/rackspace-cloud.yaml' self.netconfig_file = '/etc/network/interfaces' self.hostname_file = '/etc/hostname' def _setup_loopback(self): with open(self.netconfig_file, 'w') as iffile: iffile.write('# The loopback network interface\n') iffile.write('auto lo\n') iffile.write('iface lo inet loopback\n\n') def _setup_hostname(self, client): """ hostnamectl is available in some Debian systems and depends on dbus """ hostname = utils.get_hostname(client) completed = False if os.path.exists('/usr/bin/hostnamectl'): utils.backup_file(self.hostname_file) p = Popen( ['hostnamectl', 'set-hostname', hostname], stdout=PIPE, stderr=PIPE, stdin=PIPE ) out, err = p.communicate() if p.returncode != 0: log.error('Error using hostnamectl: {0}'.format(err)) else: # Do not run hostname since it was successful completed = True if not completed: p = Popen( ['hostname', hostname], stdout=PIPE, stderr=PIPE, stdin=PIPE ) out, err = p.communicate() if p.returncode != 0: log.error('Error using hostname: {0}'.format(err)) return p.returncode def _setup_interfaces(self, ifname, iface): with open(self.netconfig_file, 'a') as iffile: iffile.write('# Label {0}\n'.format(iface['label'])) for count, x in enumerate(iface['ips']): if count == 0: iffile.write('\nauto {0}\n'.format(ifname)) iffile.write('iface {0} inet static\n'.format(ifname)) iffile.write('\taddress {0}\n'.format(x['ip'])) iffile.write('\tnetmask {0}\n'.format(x['netmask'])) if 'gateway' in iface and iface['gateway']: iffile.write( '\tgateway {0}\n'.format( iface['gateway'] ) ) if 'dns' in iface and iface['dns']: iffile.write( '\tdns-nameservers {0}\n'.format( ' '.join(iface['dns']) ) ) if 'routes' in iface: for route in iface['routes']: iffile.write( '\tpost-up route add -net {0} netmask ' '{1} gw {2} || true\n'.format( route['route'], route['netmask'], route['gateway'] ) ) iffile.write( '\tpost-down route add -net {0} netmask ' '{1} gw {2} || true\n'.format( route['route'], route['netmask'], route['gateway'] ) ) else: iffile.write('\nauto {0}:{1}\n'.format(ifname, count)) iffile.write( 'iface {0}:{1} inet static\n'.format( ifname, count ) ) iffile.write('\taddress {0}\n'.format(x['ip'])) iffile.write('\tnetmask {0}\n'.format(x['netmask'])) if 'ip6s' in iface and iface['ip6s']: for count, ip_info in enumerate(iface['ip6s']): if count == 0: iffile.write( '\niface {0} inet6 static\n'.format(ifname) ) iffile.write('\taddress {0}\n'.format(ip_info['ip'])) iffile.write( '\tnetmask {0}\n'.format( ip_info['netmask'] ) ) if 'gateway_v6' in iface and iface['gateway_v6']: iffile.write( '\tgateway {0}\n'.format( iface['gateway_v6'] ) ) else: iffile.write( '\niface {0}:{1} inet6 static\n'.format( ifname, count ) ) iffile.write('\taddress {0}'.format(ip_info['ip'])) iffile.write( '\tnetmask {0}\n'.format( ip_info['netmask'] ) ) iffile.write('\n') def _setup_netplan(self, ifaces): # Setup netplan file from xenstore network info temp_network = { 'version': 2, 'renderer': 'networkd', 'ethernets': {} } for ifname, iface in ifaces.items(): temp_net = {'addresses': [], 'dhcp4': False} ipv4_details = iface['ips'][0] temp_net['addresses'].append( '{0}/{1}'.format( ipv4_details.get('ip'), utils.netmask_to_prefix(ipv4_details.get('netmask')) ) ) if iface.get('gateway'): temp_net['gateway4'] = iface.get('gateway') if iface.get('ip6s'): ipv6_details = iface['ip6s'][0] temp_net['dhcp6'] = False temp_net['gateway6'] = iface.get('gateway_v6') temp_net['addresses'].append( '{0}/{1}'.format( ipv6_details.get('ip'), ipv6_details.get('netmask') ) ) if iface.get('dns'): temp_net['nameservers'] = { 'addresses': iface.get('dns') } if iface.get('routes'): temp_net['routes'] = [] for route in iface.get('routes'): temp_route = {} temp_route['to'] = '{0}/{1}'.format( route.get('route'), utils.netmask_to_prefix(route.get('netmask')) ) temp_route['via'] = route.get('gateway') temp_net['routes'].append(temp_route) temp_network['ethernets'][ifname] = temp_net # Setup full dictionary and write to yaml file netplan_data = {'network': temp_network} with open(self.netplan_file, 'w') as netplan_file: yaml.dump(netplan_data, netplan_file, default_flow_style=False) def resetnetwork(self, name, value, client): ifaces = {} hostname_return_code = self._setup_hostname(client) if hostname_return_code != 0: log.error('Error setting hostname on system') xen_macs = utils.list_xenstore_macaddrs(client) for iface in utils.list_hw_interfaces(): mac = utils.get_hw_addr(iface) if not mac or mac not in xen_macs: continue ifaces[iface] = utils.get_interface(mac, client) use_netplan = False config_file = self.netconfig_file if os.path.exists('/usr/sbin/netplan'): use_netplan = True config_file = self.netplan_file # Backup original configuration file utils.backup_file(config_file) # Check if system is using netplan or not if use_netplan: # Setup netplan config file self._setup_netplan(ifaces) else: # Setup interfaces file self._setup_loopback() for ifname, iface in ifaces.items(): self._setup_interfaces(ifname, iface) if use_netplan: p = Popen( ['netplan', 'apply'], stdout=PIPE, stderr=PIPE, stdin=PIPE ) out, err = p.communicate() if p.returncode != 0: return ( str(p.returncode), 'Error applying netplan: {0}'.format(str(err)) ) else: # Loop through the interfaces and restart networking for ifname in ifaces.keys(): p = Popen( ['ifdown', ifname], stdout=PIPE, stderr=PIPE, stdin=PIPE ) out, err = p.communicate() if p.returncode != 0: return ( str(p.returncode), 'Error stopping network: {0}'.format(ifname) ) """ In some cases interfaces may retain old IP addresses especially when building from a custom image. To prevent that we will do a flush of the interface before bringing it back up. Refer to bug: https://bugs.launchpad.net/ubuntu/+source/ifupdown/+bug/1584682 """ p = Popen( ['ip', 'addr', 'flush', 'dev', ifname], stdout=PIPE, stderr=PIPE, stdin=PIPE ) out, err = p.communicate() if p.returncode != 0: return ( str(p.returncode), 'Error flushing network: {0}'.format(ifname) ) # Sleep for one second time.sleep(1) p = Popen( ['ifup', ifname], stdout=PIPE, stderr=PIPE, stdin=PIPE ) out, err = p.communicate() if p.returncode != 0: log.error( 'Error received on network restart: {0}'.format(err) ) return ( str(p.returncode), 'Error starting network: {0}'.format(ifname) ) return ('0', '') nova-agent-2.1.13/novaagent/libs/redhat.py000066400000000000000000000004151325673674100204070ustar00rootroot00000000000000 from __future__ import print_function from __future__ import absolute_import from novaagent.common import kms from novaagent.libs import centos class ServerOS(centos.ServerOS): def kmsactivate(self, name, value, client): return kms.kms_activate(value) nova-agent-2.1.13/novaagent/novaagent.py000066400000000000000000000104501325673674100201710ustar00rootroot00000000000000 from __future__ import print_function from __future__ import absolute_import import argparse import logging import time import sys import os from pyxs.connection import XenBusConnection from pyxs.client import Client from novaagent.xenbus import XenGuestRouter from novaagent.libs import centos from novaagent.libs import debian from novaagent.libs import redhat from novaagent import utils log = logging.getLogger(__name__) # Connect to Xenbus in order to interact with xenstore XENBUS_ROUTER = XenGuestRouter(XenBusConnection()) def action(server_os, client=None): for uuid in utils.list_xen_events(client): event = utils.get_xen_event(uuid, client) log.info('Event: {0} -> {1}'.format(uuid, event['name'])) command_return = ('', '') if hasattr(server_os, event['name']): run_command = getattr(server_os, event['name']) command_return = run_command(event['name'], event['value'], client) utils.remove_xenhost_event(uuid, client) message = command_return[1] return_code = command_return[0] if command_return[0] == '': return_code = '0' utils.update_xenguest_event( uuid, {'message': message, 'returncode': return_code}, client ) log.info( 'Returning {{"message": "{0}", "returncode": "{1}"}}'.format( message, return_code ) ) def nova_agent_listen(server_type, server_os): log.info('Starting actions for {0}'.format(server_type.__name__)) log.info('Checking for existence of /dev/xen/xenbus') if os.path.exists('/dev/xen/xenbus'): with Client(router=XENBUS_ROUTER) as xenbus_client: check_provider(utils.get_provider(client=xenbus_client)) while True: action(server_os, client=xenbus_client) time.sleep(1) else: check_provider(utils.get_provider()) while True: action(server_os) time.sleep(1) def get_server_type(): server_type = None if ( os.path.exists('/etc/centos-release') or os.path.exists('/etc/fedora-release') ): server_type = centos elif os.path.exists('/etc/redhat-release'): server_type = redhat elif os.path.exists('/etc/debian_version'): server_type = debian return server_type def create_parser(): parser = argparse.ArgumentParser(description='Args for novaagent') parser.add_argument( '-l', dest='loglevel', type=str, default='info', choices=('warning', 'info', 'debug'), help='log level' ) parser.add_argument( '-o', dest='logfile', default='-', type=str, help='path to log file' ) parser.add_argument( '--no-fork', dest='no_fork', default=False, type=bool, help='Perform os.fork when starting agent' ) return parser def check_provider(provider): if provider is None or provider.lower() != 'rackspace': log.error('Invalid provider for instance, agent will exit') os._exit(1) return def main(): parser = create_parser() args = parser.parse_args() loglevel = getattr(logging, args.loglevel.upper()) log_format = "%(asctime)s [%(levelname)-5.5s] %(message)s" if args.logfile == '-': logging.basicConfig( stream=sys.stdout, level=loglevel, format=log_format ) else: logging.basicConfig( filename=args.logfile, level=loglevel, format=log_format ) server_type = get_server_type() server_os = server_type.ServerOS() if args.no_fork is False: log.info('Starting daemon') try: pid = os.fork() if pid > 0: log.info('PID: {0}'.format(pid)) os._exit(0) except OSError as error: log.error( 'Unable to fork. Error: {0} {1}'.format( error.errno, error.strerror ) ) os._exit(1) else: log.info('Skipping os.fork as directed by arguments') nova_agent_listen(server_type, server_os) if __name__ == '__main__': main() nova-agent-2.1.13/novaagent/utils.py000066400000000000000000000132301325673674100173460ustar00rootroot00000000000000 from __future__ import absolute_import from novaagent.xenstore import xenstore import logging import socket import struct import fcntl import json import time import glob import os log = logging.getLogger(__name__) try: import netifaces HAS_NETIFACES = True except ImportError as exc: HAS_NETIFACES = False def encode_to_bytes(data_string): try: return bytes(data_string) except Exception: return bytes(data_string, 'utf-8') def netmask_to_prefix(netmask): return sum([bin(int(x)).count('1') for x in netmask.split('.')]) def backup_file(backup_file): if not os.path.exists(backup_file): return backup_file_suffix = '{0}.bak'.format(time.time()) log.info('Backing up -> {0} ({1})'.format(backup_file, backup_file_suffix)) os.rename( backup_file, '{0}.{1}'.format( backup_file, backup_file_suffix ) ) def get_ifcfg_files_to_remove(net_config_dir, interface_file_prefix): interfaces = [] remove_files = [] for iface in os.listdir('/sys/class/net/'): interfaces.append(net_config_dir + '/' + interface_file_prefix + iface) for filepath in glob.glob( net_config_dir + '/{0}*'.format(interface_file_prefix) ): if '.' not in filepath and filepath not in interfaces: remove_files.append(filepath) return remove_files def get_provider(client=None): provider = None try: provider_path = encode_to_bytes('vm-data/provider_data/provider') provider = xenstore.xenstore_read(provider_path, client) except Exception as e: log.error( 'Exception occurred trying to get provider: {0}'.format(str(e)) ) log.info('Provider: {0}'.format(provider)) return provider def get_hw_addr(ifname): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) try: bin_ifname = bytes(ifname[:15]) except TypeError: bin_ifname = bytes(ifname[:15], 'utf-8') try: info = fcntl.ioctl( s.fileno(), 0x8927, struct.pack('256s', bin_ifname) ) try: hw_address = ''.join( ['%02x' % ord(char) for char in info[18:24]] ).upper() except Exception: hw_address = ''.join( ['%02x' % char for char in info[18:24]] ).upper() return hw_address except IOError: if HAS_NETIFACES is False: return False iface = netifaces.ifaddresses(ifname) if netifaces.AF_LINK in iface: mac = iface[netifaces.AF_LINK][0]['addr'] return mac.replace(':', '').upper() return False def list_hw_interfaces(): if os.path.exists('/sys/class/net'): return os.listdir('/sys/class/net') return netifaces.interfaces() def get_interface(mac_address, client): interface = None try: get_interface = encode_to_bytes( 'vm-data/networking/{0}'.format(mac_address) ) interface = json.loads( xenstore.xenstore_read(get_interface, client) ) except Exception as e: log.error( 'Exception was caught getting the interface: {0}'.format(str(e)) ) log.info('Interface {0}: {1}'.format(mac_address, interface)) return interface def list_xenstore_macaddrs(client): mac_addrs = [] try: mac_addrs = xenstore.xenstore_list(b'vm-data/networking', client) except Exception as e: log.error('Exception was caught getting mac addrs: {0}'.format(str(e))) return mac_addrs def get_hostname(client): xen_hostname = None try: xen_hostname = xenstore.xenstore_read(b'vm-data/hostname', client) if xen_hostname is None: raise ValueError('Shell to xenstore-read for hostname failed') except Exception: xen_hostname = socket.gethostname() log.info('Hostname: {0}'.format(xen_hostname)) return xen_hostname def list_xen_events(client): """ After a reboot it is possible that the data/host path is not present. Once an action is passed to the instance then the path will be created and this will not generate an exception. Changing the log level to debug from error and making a better log message """ message_uuids = [] try: message_uuids = xenstore.xenstore_list(b'data/host', client) except Exception as e: log.debug( 'Exception reading data/host: {0}'.format(str(e)) ) return message_uuids def get_xen_event(uuid, client): event_detail = None get_xen_event = encode_to_bytes('data/host/{0}'.format(uuid)) try: event_detail = xenstore.xenstore_read(get_xen_event, client, True) except Exception as e: log.error( 'Exception was caught reading xen event: {0}'.format(str(e)) ) return event_detail def remove_xenhost_event(uuid, client): success = False remove_xen_event = encode_to_bytes('data/host/{0}'.format(uuid)) try: xenstore.xenstore_delete(remove_xen_event, client) success = True except Exception as e: log.error( 'Exception was caught removing xen event: {0}'.format(str(e)) ) return success def update_xenguest_event(uuid, data, client): success = False write_path = encode_to_bytes('data/guest/{0}'.format(uuid)) write_value = encode_to_bytes(json.dumps(data)) try: xenstore.xenstore_write(write_path, write_value, client) success = True except Exception as e: log.error( 'Exception was caught writing xen event: {0}'.format(str(e)) ) return success nova-agent-2.1.13/novaagent/xenbus.py000066400000000000000000000034031325673674100175130ustar00rootroot00000000000000 from pyxs.exceptions import UnexpectedPacket from pyxs.client import Router from pyxs._internal import Event from pyxs._internal import NUL from pyxs._internal import Op import select class XenGuestRouter(Router): def __call__(self): try: while True: rlist, _wlist, _xlist = select.select( [self.connection, self.r_terminator], [], []) if not rlist: continue elif self.r_terminator in rlist: break packet = self.connection.recv() if packet.op == Op.WATCH_EVENT: event = Event(*packet.payload.split(NUL)[:-1]) for monitor in self.monitors[event.token]: monitor.events.put(event) else: """ The try/except is the reason for the subclass from the pyxs package. Since this is on the guest only the below gets the packet payload and returns it without the validation piece failing. """ rvar = None try: self.rvars[packet.rq_id] rvar = self.rvars.pop(packet.rq_id, None) except Exception: temp_rq_id = list(self.rvars.keys())[0] rvar = self.rvars.pop(temp_rq_id, None) if rvar is None: raise UnexpectedPacket(packet) else: rvar.set(packet) finally: self.connection.close() self.r_terminator.close() self.w_terminator.close() nova-agent-2.1.13/novaagent/xenstore/000077500000000000000000000000001325673674100175045ustar00rootroot00000000000000nova-agent-2.1.13/novaagent/xenstore/__init__.py000066400000000000000000000000001325673674100216030ustar00rootroot00000000000000nova-agent-2.1.13/novaagent/xenstore/xenstore.py000066400000000000000000000040011325673674100217200ustar00rootroot00000000000000 from subprocess import PIPE from subprocess import Popen import json def xenstore_read(path, client, to_json=False): result = None if client is None: p = Popen( ['xenstore-read', path], stdout=PIPE, stderr=PIPE ) output, _ = p.communicate() if p.returncode == 0: result = output.decode('utf-8').strip() else: result = client.read(path).decode('utf-8').strip() if result and to_json: return json.loads(result) return result def xenstore_list(path, client): result = [] if client is None: p = Popen( ['xenstore-ls', path], stdout=PIPE, stderr=PIPE ) out, _ = p.communicate() if p.returncode == 0: decoded_out = out.decode('utf-8').split('\n') result = [ item.split(' = ')[0] for item in decoded_out if item ] else: for item in client.list(path): result.append(item.decode('utf-8').strip()) return result def xenstore_write(write_path, write_value, client): if client is None: p = Popen( ['xenstore-write', write_path, write_value], stdout=PIPE, stderr=PIPE ) p.communicate() if p.returncode != 0: raise ValueError( 'Shell to xenstore-write returned invalid code {0}'.format( p.returncode ) ) else: client.write(write_path, write_value) return def xenstore_delete(path, client): if client is None: p = Popen( ['xenstore-rm', path], stdout=PIPE, stderr=PIPE ) _out, _err = p.communicate() if p.returncode != 0: raise ValueError( 'Shell to xenstore-rm returned invalid code {0}'.format( p.returncode ) ) else: client.delete(path) return nova-agent-2.1.13/pkgs/000077500000000000000000000000001325673674100146175ustar00rootroot00000000000000nova-agent-2.1.13/pkgs/nova-agent.spec000066400000000000000000000060601325673674100175340ustar00rootroot00000000000000%if 0%{?fedora} %bcond_without python3 %endif %if 0%{?fedora} || 0%{?rhel} >= 7 %bcond_without systemd %endif %bcond_without tests Name: nova-agent Version: 2.1.0 Release: 1%{?dist} Summary: Agent for setting up clean servers on Xen License: ASL 2.0 URL: https://github.com/oldarmyc/nova-agent Source0: https://github.com/oldarmyc/nova-agent/archive/%{version}/nova-agent-%{version}.tar.gz BuildArch: noarch %{?with_systemd:BuildRequires: systemd} BuildRequires: python%{?with_python3:3}-devel BuildRequires: python%{?with_python3:3}-setuptools %if %{with tests} %{!?with_python3:BuildRequires: python-mock} BuildRequires: python%{?with_python3:3}-nose %{?el6:BuildRequires: python-unittest2} %{?el6:BuildRequires: python-argparse} BuildRequires: python%{?with_python3:3}-crypto BuildRequires: python%{?with_python3:3}-netifaces BuildRequires: python%{?with_python3:3}-pyxs %endif %{?el6:Requires: python-argparse} Requires: python%{?with_python3:3}-crypto Requires: python%{?with_python3:3}-netifaces Requires: python%{?with_python3:3}-pyxs %if %{with systemd} Requires(post): systemd Requires(preun): systemd Requires(postun): systemd %else Requires(post): chkconfig Requires(preun): chkconfig Requires(preun): initscripts Requires(postun): initscripts %endif %description Python agent for setting up clean servers on Xen using xenstore data %prep %autosetup -p 1 %build %if %{with python3} %py3_build %else %py2_build %endif %install %if %{with python3} %py3_install %else %py2_install %endif %if %{with systemd} install -Dm644 etc/nova-agent.service %{buildroot}/%{_unitdir}/nova-agent.service %else install -Dm755 etc/nova-agent.redhat %{buildroot}/%{_initddir}/nova-agent %endif %if %{with tests} %check %if %{with python3} nosetests-%{python3_version} -v %else nosetests -v %endif %endif %post %if %{with systemd} %systemd_post nova-agent.service %else chkconfig --add nova-agent %endif %preun %if %{with systemd} %systemd_preun nova-agent.service %else if [ $1 -eq 0 ]; then service nova-agent stop &> /dev/null chkconfig --del nova-agent &> /dev/null fi %endif %postun %if %{with systemd} %systemd_postun_with_restart nova-agent.service %else if [ $1 -ge 1 ]; then service nova-agent condrestart >/dev/null 2>&1 || : fi %endif %files %license LICENSE %if %{with python3} %{python3_sitelib}/novaagent* %else %{python2_sitelib}/novaagent* %endif %{_bindir}/nova-agent %if %{with systemd} %{_unitdir}/nova-agent.service %else %{_initddir}/nova-agent %endif %changelog * Wed Aug 02 2017 Carl George - 2.0.3-1 - Latest upstream - Run test suite * Mon Jun 26 2017 Dave Kludt 2.0.0-1 - Refactor code and bump to higher version so upgrade can be done * Mon Feb 15 2016 Daniel Wallace 0.2.1-1 - Always write a string to xenstore on returns * Mon Feb 01 2016 Carl George - 0.2.0-1 - Disable debug packages - Build with Python 3 on Fedora and openSUSE - openSUSE macros fixes * Fri Jan 29 2016 Carl George - 0.1.0-1 - Initial build of package nova-agent-2.1.13/run.py000066400000000000000000000001211325673674100150230ustar00rootroot00000000000000from novaagent import novaagent if __name__ == '__main__': novaagent.main() nova-agent-2.1.13/setup.py000066400000000000000000000017671325673674100154000ustar00rootroot00000000000000#!/usr/bin/env python import setuptools import novaagent import sys requirements = ['netifaces', 'pyxs', 'pycrypto', 'PyYaml'] if sys.version_info[:2] < (2, 7): requirements.append('argparse') test_requirements = ['mock', 'nose'] if sys.version_info[:2] < (2, 7): test_requirements.extend(['flake8 < 3', 'unittest2']) else: test_requirements.append('flake8') setuptools.setup( name='novaagent', version=novaagent.__version__, description=( 'Rackspace utility for reading xenstore and configuring' ' guest instance on Xen server' ), author='David Kludt', author_email='david.kludt@rackspace.com', install_requires=requirements, extras_require={ 'tests': test_requirements }, entry_points={ 'console_scripts': [ 'nova-agent=novaagent.novaagent:main' ] }, packages=[ 'novaagent', 'novaagent.libs', 'novaagent.common', 'novaagent.xenstore' ], zip_safe=False ) nova-agent-2.1.13/tests/000077500000000000000000000000001325673674100150155ustar00rootroot00000000000000nova-agent-2.1.13/tests/__init__.py000066400000000000000000000000001325673674100171140ustar00rootroot00000000000000nova-agent-2.1.13/tests/fixtures/000077500000000000000000000000001325673674100166665ustar00rootroot00000000000000nova-agent-2.1.13/tests/fixtures/__init__.py000066400000000000000000000000001325673674100207650ustar00rootroot00000000000000nova-agent-2.1.13/tests/fixtures/kms_data.py000066400000000000000000000066521325673674100210340ustar00rootroot00000000000000 UP2DATE_RETURN = """ # Automatically generated Red Hat Update Agent config file, do not edit. # Format: 1.0 versionOverride[comment]=Override the automatically determined system version versionOverride= enableProxyAuth[comment]=To use an authenticated proxy or not enableProxyAuth=0 networkRetries[comment]=Number of attempts to make at network connections before giving up networkRetries=5 hostedWhitelist[comment]=None hostedWhitelist= enableProxy[comment]=Use a HTTP Proxy enableProxy=0 serverURL[comment]=Remote server URL serverURL=https://iadproxy.rhn.rackspace.com/XMLRPC; proxyPassword[comment]=The password to use for an authenticated proxy proxyPassword= noSSLServerURL[comment]=None noSSLServerURL=http://iadproxy.rhn.rackspace.com/XMLRPC; proxyUser[comment]=The username for an authenticated proxy proxyUser= disallowConfChanges[comment]=Config options that can not be overwritten by a config update action disallowConfChanges=noReboot;sslCACert;useNoSSLForPackages;noSSLServerURL;serverURL;disallowConfChanges; sslCACert[comment]=The CA cert used to verify the ssl server sslCACert=/usr/share/rhn/RHN-ORG-TRUSTED-SSL-CERT debug[comment]=Whether or not debugging is enabled debug=0 httpProxy[comment]=HTTP proxy in host:port format, e.g. squid.redhat.com:3128 httpProxy= systemIdPath[comment]=Location of system id systemIdPath=/etc/sysconfig/rhn/systemid noReboot[comment]=Disable the reboot action noReboot=0 """ # noqa UP2DATE_READLINES = [ '\n', ( '# Automatically generated Red Hat Update ' 'Agent config file, do not edit.\n' ), '# Format: 1.0\n', ( 'versionOverride[comment]=Override the ' 'automatically determined system version\n' ), 'versionOverride=\n', '\n', 'enableProxyAuth[comment]=To use an authenticated proxy or not\n', 'enableProxyAuth=0\n', '\n', ( "networkRetries[comment]=" "Number of attempts to make at network connections before giving up\n" ), 'networkRetries=5\n', '\n', 'hostedWhitelist[comment]=None\n', 'hostedWhitelist=\n', '\n', 'enableProxy[comment]=Use a HTTP Proxy\n', 'enableProxy=0\n', '\n', 'serverURL[comment]=Remote server URL\n', 'serverURL=https://iadproxy.rhn.rackspace.com/XMLRPC;\n', '\n', 'proxyPassword[comment]=The password to use for an authenticated proxy\n', 'proxyPassword=\n', '\n', 'noSSLServerURL[comment]=None\n', 'noSSLServerURL=http://iadproxy.rhn.rackspace.com/XMLRPC;\n', '\n', 'proxyUser[comment]=The username for an authenticated proxy\n', 'proxyUser=\n', '\n', ( "disallowConfChanges[comment]=" "Config options that can not be overwritten " "by a config update action\n" ), ( "disallowConfChanges=noReboot;sslCACert;useNoSSLForPackages;" "noSSLServerURL;serverURL;disallowConfChanges;\n" ), '\n', 'sslCACert[comment]=The CA cert used to verify the ssl server\n', 'sslCACert=/usr/share/rhn/RHN-ORG-TRUSTED-SSL-CERT\n', '\n', 'debug[comment]=Whether or not debugging is enabled\n', 'debug=0\n', '\n', ( 'httpProxy[comment]=HTTP proxy in host:port ' 'format, e.g. squid.redhat.com:3128\n' ), 'httpProxy=\n', '\n', 'systemIdPath[comment]=Location of system id\n', 'systemIdPath=/etc/sysconfig/rhn/systemid\n', '\n', 'noReboot[comment]=Disable the reboot action\n', 'noReboot=0\n', '\n' ] nova-agent-2.1.13/tests/fixtures/network.py000066400000000000000000000154611325673674100207400ustar00rootroot00000000000000 CENTOS_ROUTE_FILE = [ 'ADDRESS0=10.208.0.0\n', 'NETMASK0=255.240.0.0\n', 'GATEWAY0=10.208.224.1\n', 'ADDRESS1=10.176.0.0\n', 'NETMASK1=255.240.0.0\n', 'GATEWAY1=10.208.224.1\n' ] CENTOS_IFCFG_ETH1 = [ '# Automatically generated, do not edit\n', '\n', '# Label private\n', 'BOOTPROTO=static\n', 'DEVICE=eth1\n', 'IPADDR=10.208.227.239\n', 'NETMASK=255.255.224.0\n', 'ONBOOT=yes\n', 'NM_CONTROLLED=no\n' ] CENTOS_IFCFG_ETH0 = [ '# Automatically generated, do not edit\n', '\n', '# Label public\n', 'BOOTPROTO=static\n', 'DEVICE=eth0\n', 'IPADDR=104.130.4.72\n', 'NETMASK=255.255.255.0\n', 'IPADDR1=104.130.4.73\n', 'NETMASK1=255.255.255.0\n', 'GATEWAY=104.130.4.1\n', 'IPV6INIT=yes\n', 'IPV6ADDR=2001:4802:7802:104:be76:4eff:fe20:7572/64\n', 'IPV6ADDR1=2001:4802:7802:104:be76:4eff:fe20:7573/64\n', 'IPV6_DEFAULTGW=fe80::def%eth0\n', 'DNS1=69.20.0.164\n', 'DNS2=69.20.0.196\n', 'ONBOOT=yes\n', 'NM_CONTROLLED=no\n' ] ETH0_INTERFACE = { 'ip6s': [ { 'ip': '2001:4802:7802:104:be76:4eff:fe20:7572', 'netmask': 64, 'enabled': '1', 'gateway': 'fe80::def' }, { 'ip': '2001:4802:7802:104:be76:4eff:fe20:7573', 'netmask': 64, 'enabled': '1', 'gateway': 'fe80::def' } ], 'label': 'public', 'broadcast': '104.130.4.255', 'ips': [ { 'ip': '104.130.4.72', 'netmask': '255.255.255.0', 'enabled': '1', 'gateway': '104.130.4.1' }, { 'ip': '104.130.4.73', 'netmask': '255.255.255.0', 'enabled': '1', 'gateway': '104.130.4.1' } ], 'mac': 'BC:76:4E:20:75:72', 'gateway_v6': 'fe80::def', 'dns': [ '69.20.0.164', '69.20.0.196' ], 'gateway': '104.130.4.1' } ALL_INTERFACES = { 'eth2': { 'broadcast': '192.168.5.255', 'ips': [ { 'ip': '192.168.5.4', 'netmask': '255.255.255.0', 'enabled': '1', 'gateway': None } ], 'mac': 'BC:76:4E:20:3B:70', 'gateway': None, 'label': 'test-interface-2' }, 'eth0': { 'ip6s': [ { 'ip': '2001:4802:7803:104:be76:4eff:fe20:5eb2', 'netmask': 64, 'enabled': '1', 'gateway': 'fe80::def' } ], 'label': 'public', 'broadcast': '104.130.169.255', 'ips': [ { 'ip': '104.130.169.159', 'netmask': '255.255.255.0', 'enabled': '1', 'gateway': '104.130.169.1' } ], 'mac': 'BC:76:4E:20:5E:B2', 'gateway_v6': 'fe80::def', 'dns': ['69.20.0.164', '69.20.0.196'], 'gateway': '104.130.169.1' }, 'eth1': { 'label': 'private', 'broadcast': '10.176.223.255', 'ips': [ { 'ip': '10.176.195.183', 'netmask': '255.255.224.0', 'enabled': '1', 'gateway': None } ], 'mac': 'BC:76:4E:20:5E:FB', 'routes': [ { 'route': '10.208.0.0', 'netmask': '255.240.0.0', 'gateway': '10.176.192.1' }, { 'route': '10.176.0.0', 'netmask': '255.240.0.0', 'gateway': '10.176.192.1' } ], 'gateway': None } } CENTOS_NETWORK_FILE = [ 'NETWORKING=yes\n', 'NOZEROCONF=yes\n', 'NETWORKING_IPV6=yes\n', 'HOSTNAME=test_hostname\n' ] DEBIAN_INTERFACES_CONFIG = [ '#This is a test file\n', '# Label public\n', '\n', 'auto eth0\n', 'iface eth0 inet static\n', '\taddress 104.130.4.72\n', '\tnetmask 255.255.255.0\n', '\tgateway 104.130.4.1\n', '\tdns-nameservers 69.20.0.164 69.20.0.196\n', '\n', 'auto eth0:1\n', 'iface eth0:1 inet static\n', '\taddress 104.130.4.73\n', '\tnetmask 255.255.255.0\n', '\n', 'iface eth0 inet6 static\n', '\taddress 2001:4802:7802:104:be76:4eff:fe20:7572\n', '\tnetmask 64\n', '\tgateway fe80::def\n', '\n', 'iface eth0:1 inet6 static\n', '\taddress 2001:4802:7802:104:be76:4eff:fe20:7573\tnetmask 64\n', '\n', '# Label private\n', '\n', 'auto eth1\n', 'iface eth1 inet static\n', '\taddress 10.208.227.239\n', '\tnetmask 255.255.224.0\n', ( '\tpost-up route add -net 10.208.0.0 netmask 255.' '240.0.0 gw 10.208.224.1 || true\n' ), ( '\tpost-down route add -net 10.208.0.0 netmask 255.' '240.0.0 gw 10.208.224.1 || true\n' ), ( '\tpost-up route add -net 10.176.0.0 netmask 255.' '240.0.0 gw 10.208.224.1 || true\n' ), ( '\tpost-down route add -net 10.176.0.0 netmask 255.' '240.0.0 gw 10.208.224.1 || true\n' ), '\n' ] DEBIAN_NETPLAN_CONFIG = [ 'network:\n', ' ethernets:\n', ' eth0:\n', ' addresses:\n', ' - 104.130.4.72/24\n', ' - 2001:4802:7802:104:be76:4eff:fe20:7572/64\n', ' dhcp4: false\n', ' dhcp6: false\n', ' gateway4: 104.130.4.1\n', ' gateway6: fe80::def\n', ' nameservers:\n', ' addresses:\n', ' - 69.20.0.164\n', ' - 69.20.0.196\n', ' eth1:\n', ' addresses:\n', ' - 10.208.227.239/19\n', ' dhcp4: false\n', ' routes:\n', ' - to: 10.208.0.0/12\n', ' via: 10.208.224.1\n', ' - to: 10.176.0.0/12\n', ' via: 10.208.224.1\n', ' renderer: networkd\n', ' version: 2\n' ] DEBIAN_INTERFACES_LOOPBACK = [ '# The loopback network interface\n', 'auto lo\n', 'iface lo inet loopback\n', '\n' ] UBUNTU_NETPLAN_CONFIG = [ 'network:\n', ' ethernets:\n', ' eth0:\n', ' addresses:\n', ' - 104.130.169.159/24\n', ' - 2001:4802:7803:104:be76:4eff:fe20:5eb2/64\n', ' dhcp4: false\n', ' dhcp6: false\n', ' gateway4: 104.130.169.1\n', ' gateway6: fe80::def\n', ' nameservers:\n', ' addresses:\n', ' - 69.20.0.164\n', ' - 69.20.0.196\n', ' eth1:\n', ' addresses:\n', ' - 10.176.195.183/19\n', ' dhcp4: false\n', ' routes:\n', ' - to: 10.208.0.0/12\n', ' via: 10.176.192.1\n', ' - to: 10.176.0.0/12\n', ' via: 10.176.192.1\n', ' eth2:\n', ' addresses:\n', ' - 192.168.5.4/24\n', ' dhcp4: false\n', ' renderer: networkd\n', ' version: 2\n' ] nova-agent-2.1.13/tests/fixtures/utils_data.py000066400000000000000000000025541325673674100213770ustar00rootroot00000000000000 def get_hostname(use_bytes=True): if use_bytes: return (b'test-server\n', b'') else: return 'test-server' def get_xen_host_events(): return ( b""" 748dee41-c47f-4ec7-b2cd-037e51da4031 = "{"name": "keyinit"\n""", b'' ) def get_xen_guest_events(): return ( b"""cd4ae803-1577-4e37-90b3-3de01bc4bba9 = "{"message": "1.39.1"}"\n 78b3c098-46b3-4a54-b2ff-d2ac15651716 = "{"message": "kmsactivate"}"\n bb966d88-e06c-499f-b19b-60c06c9e257a = "{"returncode": "0"}"\n""", b'' ) def get_xen_host_event_details(): return ( b'{"name": "keyinit", "value": "68436575764933852815830951574296"}\n', b'' ) def get_mac_addresses(): return ( b""" BC764E206C5B = "{"label": "private", "broadcast": "10.208.255.255", "ips": [\\..."\n BC764E206C5A = "{"ip6s": [{"ip": "2001:4802:7802:104:be76:4eff:fe20:6c5a", "\\..."\n""", # noqa b'' ) def get_network_interface(): return ( b""" {"label": "private", "broadcast": "10.208.255.255", "ips": [ {"ip": "10.208.227.239", "netmask": "255.255.224.0", "enabled": "1", "gateway": null}], "mac": "BC:76:4E:20:6C:5B", "routes": [ {"route": "10.208.0.0", "netmask": "255.240.0.0", "gateway": "10.208.224.1"}, {"route": "10.176.0.0", "netmask": "255.240.0.0", "gateway": "10.208.224.1"}], "gateway": null}\n""", b'' ) nova-agent-2.1.13/tests/fixtures/xen_data.py000066400000000000000000000101271325673674100210240ustar00rootroot00000000000000 def get_hostname(use_bytes=True): if use_bytes: return b'test-server\n' else: return 'test-server' def get_xen_host_events(): return [ b'748dee41-c47f-4ec7-b2cd-037e51da4031' ] def get_xen_host_event_details(): return ( b'{"name": "keyinit", "value": "68436575764933852815830951574296"}\n' ) def get_mac_addresses(): return [ b'BC764E206C5B', b'BC764E206C5A' ] def get_network_interface(): return b""" {"label": "private", "broadcast": "10.208.255.255", "ips": [ {"ip": "10.208.227.239", "netmask": "255.255.224.0", "enabled": "1", "gateway": null}], "mac": "BC:76:4E:20:6C:5B", "routes": [ {"route": "10.208.0.0", "netmask": "255.240.0.0", "gateway": "10.208.224.1"}, {"route": "10.176.0.0", "netmask": "255.240.0.0", "gateway": "10.208.224.1"}], "gateway": null}\n""" def check_network_interface(): return { 'label': 'private', 'ips': [ { 'ip': '10.208.227.239', 'gateway': None, 'enabled': '1', 'netmask': '255.255.224.0' } ], 'broadcast': '10.208.255.255', 'mac': 'BC:76:4E:20:6C:5B', 'gateway': None, 'routes': [ { 'gateway': '10.208.224.1', 'route': '10.208.0.0', 'netmask': '255.240.0.0' }, { 'gateway': '10.208.224.1', 'route': '10.176.0.0', 'netmask': '255.240.0.0' } ] } def get_iface_from_netifaces(): return { 17: [ { 'broadcast': 'ff:ff:ff:ff:ff:ff', 'addr': 'bc:76:4e:20:5a:79' } ], 2: [ { 'broadcast': '10.176.223.255', 'netmask': '255.255.224.0', 'addr': '10.176.198.15' } ], 10: [ { 'netmask': 'ffff:ffff:ffff:ffff::', 'addr': 'fe80::be76:4eff:fe20:5a79%eth1' } ] } FCNTL_INFO_BYTES = b'eth1\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\xbcvN \x12\xb3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' # noqa FNCTL_INFO_STRING = 'eth1\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\xbcvN \x12\xb3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' # noqa nova-agent-2.1.13/tests/tests_common_file_inject.py000066400000000000000000000152301325673674100224350ustar00rootroot00000000000000 from novaagent.common import file_inject import logging import base64 import shutil import stat import glob import sys import os if sys.version_info[:2] >= (2, 7): from unittest import TestCase else: from unittest2 import TestCase try: from unittest import mock except ImportError: import mock class TestHelpers(TestCase): def setUp(self): logging.disable(logging.ERROR) if not os.path.exists('/tmp/test_file'): with open('/tmp/test_file', 'a+') as f: f.write('This is a test file') os.utime('/tmp/test_file', None) fd = os.open('/tmp/test_file', os.O_RDONLY) os.fchmod( fd, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH ) def tearDown(self): logging.disable(logging.NOTSET) files = glob.glob('/tmp/test_file*') for item in files: os.remove(item) try: shutil.rmtree('/tmp/tests') except Exception: pass # Fix for python 2.x def permissions_to_unix_name(self, os_stat): is_dir = 'd' if stat.S_ISDIR(os_stat.st_mode) else '-' permissions_dict = { '7': 'rwx', '6': 'rw-', '5': 'r-x', '4': 'r--', '0': '---' } perms = str(oct(os_stat.st_mode)[-3:]) readable_perms = is_dir + ''.join( permissions_dict.get(x, x) for x in perms ) return readable_perms def test_file_permission(self): class MockStat(object): def __init__(self): self.st_mode = 33188 self.st_uid = 1001 self.st_gid = 1001 with mock.patch('novaagent.common.file_inject.os.stat') as stat: stat.return_value = MockStat() mode, uid, gid = file_inject._get_file_permissions( '/tmp/test_file' ) self.assertEqual(mode, 33188, 'Mode is not expected value') self.assertEqual(uid, 1001, 'UID is not expected value') self.assertEqual(gid, 1001, 'GID is not expected value') def test_file_permission_exception(self): os.remove('/tmp/test_file') mode, uid, gid = file_inject._get_file_permissions('/tmp/test_file') self.assertEqual(mode, None, 'Mode is not expected value') self.assertEqual(uid, 0, 'UID is not expected value') self.assertEqual(gid, 0, 'GID is not expected value') def test_write_file(self): file_inject._write_file( '/tmp/test_file_write', 'File Contents' ) files = glob.glob('/tmp/test_file*') self.assertEqual( len(files), 2, 'Did not find any files' ) found_file = False temp_contents = None for f in files: if '/tmp/test_file_write' == f: with open(f) as temp_file: temp_contents = temp_file.read() found_file = True assert found_file, 'Did not find written file in expected path' self.assertEqual( temp_contents, 'File Contents', 'Written data in file is not what was expected' ) permissions = os.stat('/tmp/test_file_write') try: readable_perms = stat.filemode(permissions.st_mode) except Exception: readable_perms = self.permissions_to_unix_name(permissions) self.assertEqual( readable_perms, '-rw-------', 'Permissions are not 600 as expected' ) def test_write_file_existing_file(self): file_inject._write_file( '/tmp/test_file', 'File Contents' ) files = glob.glob('/tmp/test_file*') self.assertEqual( len(files), 2, 'Did not find any files' ) found_file = False temp_contents = None for f in files: if '/tmp/test_file' == f: with open(f) as temp_file: temp_contents = temp_file.read() found_file = True assert found_file, 'Did not find written file in expected path' self.assertEqual( temp_contents, 'File Contents', 'Written data in file is not what was expected' ) permissions = os.stat('/tmp/test_file') try: readable_perms = stat.filemode(permissions.st_mode) except Exception: readable_perms = self.permissions_to_unix_name(permissions) self.assertEqual( readable_perms, '-rw-r--r--', 'Permissions are not 644 as expected' ) def test_instantiate_file_inject(self): file_inject.FileInject() assert True, 'Class did not generate exception' def test_inject_file_cmd(self): test = file_inject.FileInject() encode_details = base64.b64encode( b'/tmp/tests/test_file_write,Testing the inject' ) error, message = test.injectfile_cmd(encode_details) self.assertEqual(error, "0", "Did not get expected error code") self.assertEqual( message, "", "Did not get expected message on success" ) files = glob.glob('/tmp/tests/test_file*') self.assertEqual( len(files), 1, 'Did not find any files' ) found_file = False temp_contents = None for f in files: if '/tmp/tests/test_file_write' == f: with open(f) as temp_file: temp_contents = temp_file.read() found_file = True assert found_file, 'Did not find written file in expected path' self.assertEqual( temp_contents, 'Testing the inject', 'Written data in file is not what was expected' ) permissions = os.stat('/tmp/tests/test_file_write') try: readable_perms = stat.filemode(permissions.st_mode) except Exception: readable_perms = self.permissions_to_unix_name(permissions) self.assertEqual( readable_perms, '-rw-------', 'Permissions are not 600 as expected' ) def test_inject_file_cmd_exception(self): test = file_inject.FileInject() error, message = test.injectfile_cmd('Unencoded data') self.assertEqual(error, "500", "Did not get expected error code") self.assertEqual( message, "Error doing base64 decoding of data", "Did not get expected message on error" ) nova-agent-2.1.13/tests/tests_common_kms.py000066400000000000000000000103071325673674100207540ustar00rootroot00000000000000 from novaagent.common import kms from .fixtures import kms_data import logging import glob import os import sys if sys.version_info[:2] >= (2, 7): from unittest import TestCase else: from unittest2 import TestCase try: from unittest import mock except ImportError: import mock class TestHelpers(TestCase): def setUp(self): logging.disable(logging.ERROR) def tearDown(self): logging.disable(logging.NOTSET) files = glob.glob('/tmp/up2date*') for item in files: os.remove(item) def test_register_with_rhn_success(self): with open('/tmp/systemid', 'a+') as f: f.write('This is a test file') kms.SYSTEMID_PATH = '/tmp/systemid' with mock.patch('novaagent.common.kms.subprocess.Popen') as popen: popen.return_value.pip = 99 with mock.patch('novaagent.common.kms.os.waitpid') as waitpid: waitpid.return_value = ('', 0) message = kms.register_with_rhn('activation_key', 'profile') self.assertEqual( message, None, 'Data was returned when should not have been' ) def test_register_with_rhn_failure(self): with open('/tmp/systemid', 'a+') as f: f.write('This is a test file') kms.SYSTEMID_PATH = '/tmp/systemid' with mock.patch('novaagent.common.kms.subprocess.Popen') as popen: popen.return_value.pip = 99 with mock.patch('novaagent.common.kms.os.waitpid') as waitpid: waitpid.return_value = ('Error registering', 1) message = kms.register_with_rhn('activation_key', 'profile') self.assertEqual( message, ("500", "Couldn't activate with RHN: 1"), 'Data was returned when should not have been' ) def test_configure_up2date(self): up2date = kms.configure_up2date(['iadproxy.rhn.rackspace.com']) kms.UP2DATE_PATH = '/etc/sysconfig/rhn/up2date' self.assertEqual( up2date.get('/etc/sysconfig/rhn/up2date'), kms_data.UP2DATE_RETURN, 'Up2date data was not the expected value' ) def test_kms_activate(self): test_data = { 'activation_key': 'activation_key', 'profile': 'kms_profile', 'domains': 'iadproxy.rhn.rackspace.com' } kms.UP2DATE_PATH = '/tmp/up2date' with mock.patch('novaagent.common.kms.register_with_rhn') as reg: reg.return_value = None success = kms.kms_activate(test_data) self.assertEqual( success, ("0", ""), 'Return value was not expected value' ) files = glob.glob('/tmp/up2date*') self.assertEqual( len(files), 1, 'Did not find written file' ) with open('/tmp/up2date') as f: written_data = f.readlines() for index, line in enumerate(written_data): self.assertEqual( line, kms_data.UP2DATE_READLINES[index], 'Written file did not match expected value' ) def test_kms_activate_error(self): test_data = { 'activation_key': 'activation_key', 'profile': 'kms_profile', 'domains': 'iadproxy.rhn.rackspace.com' } kms.UP2DATE_PATH = '/tmp/up2date' with mock.patch('novaagent.common.kms.register_with_rhn') as reg: reg.return_value = ("500", "Couldn't activate with RHN") success = kms.kms_activate(test_data) self.assertEqual( success, ("500", "Couldn't activate with RHN"), 'Return value was not expected value' ) files = glob.glob('/tmp/up2date*') self.assertEqual( len(files), 1, 'Did not find written file' ) with open('/tmp/up2date') as f: written_data = f.readlines() for index, line in enumerate(written_data): self.assertEqual( line, kms_data.UP2DATE_READLINES[index], 'Written file did not match expected value' ) nova-agent-2.1.13/tests/tests_common_password.py000066400000000000000000000347171325673674100220370ustar00rootroot00000000000000 from novaagent.common import password import logging import base64 import glob import sys import os if sys.version_info[:2] >= (2, 7): from unittest import TestCase else: from unittest2 import TestCase try: from unittest import mock except ImportError: import mock if sys.version_info > (3,): long = int class TestHelpers(TestCase): def setUp(self): logging.disable(logging.ERROR) def tearDown(self): logging.disable(logging.NOTSET) files = glob.glob('/tmp/passwd*') for item in files: os.remove(item) def test_password_error(self): test_error = ('000', 'Test Response') test = password.PasswordError(test_error) self.assertEqual( test.__str__(), '000: Test Response', 'Response str did not match expected value' ) self.assertEqual( test.get_response(), test_error, 'Response returned did not match expected value' ) def test_password_commands_init(self): test = password.PasswordCommands() self.assertEqual( test.prime, 162259276829213363391578010288127, 'Prime values do not match' ) self.assertEqual(test.base, 5, 'Base values do not match') self.assertEqual( test.min_key_length, 540, "Invalid key length on init" ) self.assertEqual(test._public, None, "Public is not none") self.assertEqual(test._private, None, "Private is not none") self.assertEqual(test._shared, None, "Shared is not none") self.assertEqual(test._aes_key, None, "AES key is not none") self.assertEqual(test._aes_iv, None, "AES IV is not none") def test_change_password_bytes(self): test = password.PasswordCommands() test_password = b'test_password\n' with mock.patch('novaagent.common.password.set_password'): try: test._change_password(test_password) except Exception: assert False, 'An error was generated when should not have' def test_change_password_string(self): test = password.PasswordCommands() test_password = 'test_password\n' with mock.patch('novaagent.common.password.set_password'): try: test._change_password(test_password) except Exception: assert False, 'An error was generated when should not have' def test_make_private_key(self): test = password.PasswordCommands() test._generate_private_key() self.assertEqual( type(test._private), long, 'Invalid return type from make key' ) try: self.assertGreaterEqual( test._private.bit_length(), test.min_key_length, 'Incorrect bit length in private key' ) except AttributeError: self.assertGreaterEqual( len(bin(test._private)) - 2, test.min_key_length, 'Incorrect bit length in private key' ) def test_compute_public_key(self): test = password.PasswordCommands() test._generate_private_key() test._compute_public_key() self.assertEqual( type(test._public), long, 'Invalid return type returned from compute public' ) def test_compute_shared_key(self): test = password.PasswordCommands() test._private = int(""" 23112120562215754241813840772170184083273863303098366811852003357 72446841869122972713534217535689064137278608958579090107008875567 5269543831650785847026033312 46342023613076766721726""".replace('\n', '').replace(' ', '')) temp_public = 29146890515040234272807524713655 test._compute_shared_key(temp_public) self.assertEqual( test._shared, 27234591073885988013566387861589, 'Shared key does not match expected value' ) def test_aes_key(self): test = password.PasswordCommands() test._compute_aes_key() self.assertEqual( test._aes_key, b'j\xdf\x97\xf8:\xcfdS\xd4\xa6\xa4\xb1\x07\x0f7T', 'AES key was not expected value' ) self.assertEqual( test._aes_iv, b'#d\r\xec6\x8f\xbe\xf3\x03dp\xfcTe\xb8e', 'AES IV set was not expected value' ) def test_clear_data(self): test = password.PasswordCommands() test._generate_private_key() test._compute_public_key() test._aes_key = 'Test AES' test._aes_iv = 'Test AES IV' test._wipe_keys() self.assertEqual(test._aes_key, None, "AES key is not None") self.assertEqual(test._aes_iv, None, "AES IV is not None") self.assertEqual(test._private, None, "Private is not None") self.assertEqual(test._public, None, "Public key is not None") self.assertEqual(test._shared, None, "Shared key is not None") def test_key_init(self): test = password.PasswordCommands() try: keyinit = test.keyinit_cmd(242416858127415443985927051233248666254) except Exception: assert False, 'Key init caused an error' self.assertNotEqual(test._private, None, 'Private is None') self.assertNotEqual(test._public, None, 'Public is None') self.assertNotEqual(test._shared, None, 'Shared is None') self.assertNotEqual(test._aes_key, None, 'AES key is None') self.assertNotEqual(test._aes_iv, None, 'AES IV is None') self.assertEqual( keyinit[0], 'D0', 'Unexpected first value of tuple' ) self.assertEqual( type(keyinit[1]), str, 'Unexpected type on second value of tuple should be string' ) def test_decode_password_base64_error(self): test = password.PasswordCommands() try: test._decode_password(password) assert False, 'Exception was not caught' except password.PasswordError as e: self.assertEqual( str(e), "500: Couldn't decode base64 data", 'Incorrect message received on exception' ) def test_decode_password_no_key_exchange(self): temp_pass = base64.b64encode(b'this is a test') test = password.PasswordCommands() try: test._decode_password(temp_pass) assert False, 'Exception was not caught' except password.PasswordError as e: self.assertEqual( str(e), "500: Password without key exchange", 'Incorrect message received on AES error' ) def test_decode_password_password_exception(self): temp_pass = base64.b64encode(b'this is a test') test = password.PasswordCommands() test._compute_aes_key() password_error = password.PasswordError((999, "Generate Exception")) with mock.patch( 'novaagent.common.password.PasswordCommands._decrypt_password', side_effect=password_error ): try: test._decode_password(temp_pass) assert False, 'A PasswordError exception shouldhave occurred' except password.PasswordError: pass except Exception: assert False, 'PasswordError exception was not triggered' def test_decode_password_general_exception(self): temp_pass = base64.b64encode(b'this is a test') test = password.PasswordCommands() test._compute_aes_key() with mock.patch( 'novaagent.common.password.PasswordCommands._decrypt_password', side_effect=ValueError('This is a test') ): try: test._decode_password(temp_pass) assert False, 'A PasswordError should have occurred' except password.PasswordError: pass except Exception: assert False, 'A PasswordError should have been raised' def test_decode_password_success(self): temp_pass = base64.b64encode(b'this is a test') test = password.PasswordCommands() test._compute_aes_key() with mock.patch( 'novaagent.common.password.PasswordCommands._decrypt_password', ) as decrypt: decrypt.return_value = 'test_password' try: returned_password = test._decode_password(temp_pass) except Exception: assert False, 'An exception occurred and should not have' self.assertEqual( returned_password, 'test_password', 'Password returned does not match' ) def test_decode_password_password_error_length(self): temp_pass = base64.b64encode(b'this is a test') test = password.PasswordCommands() test._aes_key = b"\xf8\x05\x98\xbb '\xeeM<=\xe2\x8eU\xf6E\xa1" test._aes_iv = b';\xd1\xacR|:\xc2\xdd#t\x181\xad\x11d\x0b' try: test._decode_password(temp_pass) assert False, 'Exception was not caught' except password.PasswordError as e: self.assertEqual( str(e), "500: Input strings must be a multiple of 16 in length", 'Incorrect message received generic password error' ) def test_password_cmd_invalid_password_data(self): test = password.PasswordCommands() test._aes_key = b"\xf8\x05\x98\xbb '\xeeM<=\xe2\x8eU\xf6E\xa1" test._aes_iv = b';\xd1\xacR|:\xc2\xdd#t\x181\xad\x11d\x0b' message = test.password_cmd( "6E6haX/YGRSEcR9X9+3nLOgD+ItDTv9/uOHms02Cos0sqI/k1uFIC3V/YNydHJOk" ) self.assertEqual( (500, 'Invalid password data received'), message, 'Did not receive expected error on invalid password data' ) def test_password_cmd_success(self): test = password.PasswordCommands() test._aes_key = 'AES Key' test._aes_iv = 'AES IV' test._private = 'Private' test._shared = 'Shared' test._public = 'Public' with mock.patch( 'novaagent.common.password.PasswordCommands._decode_password' ) as decode: decode.return_value = 'test' with mock.patch( 'novaagent.common.password.PasswordCommands._change_password' ): message = test.password_cmd( '6E6haX/YGRSEcR9X9+3nLOgD+ItDTv9/' 'uOHms02Cos0sqI/k1uFIC3V/YNydHJOk' ) self.assertEqual(test._aes_key, None, "AES key is not None") self.assertEqual(test._aes_iv, None, "AES IV is not None") self.assertEqual(test._private, None, "Private is not None") self.assertEqual(test._public, None, "Public key is not None") self.assertEqual(test._shared, None, "Shared key is not None") self.assertEqual( ("0", ""), message, 'Did not receive expected message on change password' ) def test_password_cmd_error(self): test = password.PasswordCommands() password_error = password.PasswordError((999, "Generate Exception")) with mock.patch( 'novaagent.common.password.PasswordCommands._decode_password', side_effect=password_error ): message = test.password_cmd('Test Pass') self.assertEqual( (999, "Generate Exception"), message, 'Did not receive expected message on change password exception' ) def test_set_password_success(self): mock_popen = mock.Mock() mock_comm = mock.Mock() mock_comm.return_value = ('out', 'error') mock_popen.side_effect = [ mock.Mock(returncode=0, communicate=mock_comm) ] try: with mock.patch( 'novaagent.common.password.Popen', side_effect=mock_popen ): password.set_password('test', 'test') except Exception: assert False, 'Exception should not have been raised' def test_set_password_success_bytes(self): mock_popen = mock.Mock() mock_comm = mock.Mock() mock_comm.return_value = ('out', 'error') mock_stdin = mock.Mock() mock_stdin.write.side_effect = [TypeError(), None] mock_popen.side_effect = [ mock.Mock(returncode=0, communicate=mock_comm, stdin=mock_stdin) ] try: with mock.patch( 'novaagent.common.password.Popen', side_effect=mock_popen ): returned = password.set_password('test', 'test') self.assertEqual(returned, None, 'Invalid return value on success') except Exception: assert False, 'Exception should not have been raised' def test_set_password_success_string(self): mock_popen = mock.Mock() mock_comm = mock.Mock() mock_comm.return_value = ('out', 'error') mock_stdin = mock.Mock() mock_stdin.side_effect = [None] mock_popen.side_effect = [ mock.Mock(returncode=0, communicate=mock_comm, stdin=mock_stdin) ] try: with mock.patch( 'novaagent.common.password.Popen', side_effect=mock_popen ): returned = password.set_password('test', 'test') self.assertEqual(returned, None, 'Invalid return value on success') except Exception: assert False, 'Exception should not have been raised' def test_set_password_bad_return(self): mock_popen = mock.Mock() mock_comm = mock.Mock() mock_comm.return_value = ('out', 'error') mock_popen.side_effect = [ mock.Mock(returncode=999, communicate=mock_comm) ] try: with mock.patch( 'novaagent.common.password.Popen', side_effect=mock_popen ): password.set_password('test', 'test') assert False, 'Exception should have been raised' except Exception as e: self.assertEqual( str(e), '500: Failed to change password for test: 999 : error', 'Invalid message received for failure on passwd cmd' ) nova-agent-2.1.13/tests/tests_init.py000066400000000000000000000044511325673674100175600ustar00rootroot00000000000000 from novaagent import libs import novaagent import logging import sys if sys.version_info[:2] >= (2, 7): from unittest import TestCase else: from unittest2 import TestCase try: from unittest import mock except ImportError: import mock class TestHelpers(TestCase): def setUp(self): logging.disable(logging.ERROR) def tearDown(self): logging.disable(logging.NOTSET) def test_version(self): self.assertEqual( novaagent.__version__, '2.1.13', 'Version expected was not returned correctly' ) def test_libs_init_version(self): temp = libs.DefaultOS() self.assertEqual( temp.version('Name', 'Value', 'Client'), ('0', '2.1.13'), 'Did not get expected value on version' ) def test_libs_init_features(self): temp = libs.DefaultOS() self.assertEqual( temp.features('Name', 'Value', 'Client'), ( '0', 'kmsactivate,resetnetwork,version,keyinit,' 'features,password,injectfile' ), 'Did not get expected value on features' ) def test_libs_init_inject_file(self): temp = libs.DefaultOS() with mock.patch('novaagent.libs.FileInject.injectfile_cmd') as fin: fin.return_value = ('0', '') self.assertEqual( temp.injectfile('Name', 'Value', 'Client'), ('0', ''), 'Did not get expected value on file inject' ) def test_libs_init_password(self): temp = libs.DefaultOS() with mock.patch('novaagent.libs.PasswordCommands.password_cmd') as pas: pas.return_value = ('0', '') self.assertEqual( temp.password('Name', 'Value', 'Client'), ('0', ''), 'Did not get expected value on password' ) def test_libs_init_key_init(self): temp = libs.DefaultOS() with mock.patch('novaagent.libs.PasswordCommands.keyinit_cmd') as key: key.return_value = ('0', '') self.assertEqual( temp.keyinit('Name', 'Value', 'Client'), ('0', ''), 'Did not get expected value on keyinit' ) nova-agent-2.1.13/tests/tests_libs_centos.py000066400000000000000000000700261325673674100211220ustar00rootroot00000000000000 from novaagent.libs import centos from .fixtures import xen_data from .fixtures import network import logging import glob import sys import os if sys.version_info[:2] >= (2, 7): from unittest import TestCase else: from unittest2 import TestCase try: from unittest import mock except ImportError: import mock class TestHelpers(TestCase): def setUp(self): logging.disable(logging.ERROR) def tearDown(self): logging.disable(logging.NOTSET) file_searches = [ '/tmp/route-*', '/tmp/ifcfg-eth*', '/tmp/hostname*', '/tmp/network*', '/tmp/ifcfg-lo*' ] for search in file_searches: route_files = glob.glob(search) for item in route_files: os.remove(item) def setup_temp_route(self): with open('/tmp/route-eth1', 'a+') as f: f.write('This is a test file') def setup_temp_interface_config(self, interface): with open('/tmp/ifcfg-{0}'.format(interface), 'a+') as f: f.write('This is a test file') def setup_temp_hostname(self): with open('/tmp/hostname', 'a+') as f: f.write('This is a test file') def setup_temp_network(self): with open('/tmp/network', 'a+') as f: f.write('This is a test file') def test_initialization(self): temp = centos.ServerOS() self.assertEqual( temp.netconfig_dir, '/etc/sysconfig/network-scripts', 'Network scripts directory was not expected value' ) self.assertEqual( temp.interface_file_prefix, 'ifcfg', 'Network scripts prefix is not expected value' ) self.assertEqual( temp.route_file_prefix, 'route', 'Route script prefix is not expected value' ) self.assertEqual( temp.hostname_file, '/etc/hostname', 'Hostname file is not expected value' ) self.assertEqual( temp.network_file, '/etc/sysconfig/network', 'Network file location is not expected value' ) def test_reset_network_hostname_failure(self): self.setup_temp_route() self.setup_temp_interface_config('eth1') self.setup_temp_interface_config('lo') self.setup_temp_network() temp = centos.ServerOS() temp.netconfig_dir = '/tmp' temp.network_file = '/tmp/network' with mock.patch( 'novaagent.libs.centos.ServerOS._setup_hostname' ) as hostname: hostname.return_value = 1, 'test_hostname' with mock.patch('novaagent.utils.list_xenstore_macaddrs') as mac: mac.return_value = ['BC764E206C5B'] with mock.patch('novaagent.utils.list_hw_interfaces') as hwint: hwint.return_value = ['eth1', 'lo'] mock_response = mock.Mock() mock_response.side_effect = [ 'BC764E206C5B', None ] with mock.patch( 'novaagent.utils.get_hw_addr', side_effect=mock_response ): with mock.patch( 'novaagent.utils.get_interface' ) as inter: inter.return_value = ( xen_data.check_network_interface() ) with mock.patch( 'novaagent.utils.get_ifcfg_files_to_remove' ) as ifcfg_files: ifcfg_files.return_value = ['/tmp/ifcfg-eth1'] with mock.patch( 'novaagent.libs.centos.Popen' ) as p: p.return_value.communicate.return_value = ( 'out', 'error' ) p.return_value.returncode = 0 result = temp.resetnetwork( 'name', 'value', 'dummy_client' ) self.assertEqual( result, ('0', ''), 'Result was not the expected value' ) network_files = glob.glob('/tmp/network*') self.assertEqual( len(network_files), 2, 'Incorrect number of network files' ) ifcfg_files = glob.glob('/tmp/ifcfg-eth*') self.assertEqual( len(ifcfg_files), 2, 'Incorrect number of ifcfg files' ) route_files = glob.glob('/tmp/route*') self.assertEqual( len(route_files), 2, 'Incorrect number of route files' ) localhost = glob.glob('/tmp/ifcfg-lo') self.assertEqual( len(localhost), 1, 'Localhost ifcfg file was moved out of the way and should not have' ) def test_reset_network_flush_failure(self): self.setup_temp_route() self.setup_temp_interface_config('eth1') self.setup_temp_interface_config('lo') self.setup_temp_network() temp = centos.ServerOS() temp.netconfig_dir = '/tmp' temp.network_file = '/tmp/network' with mock.patch( 'novaagent.libs.centos.ServerOS._setup_hostname' ) as hostname: hostname.return_value = 0, 'test_hostname' with mock.patch('novaagent.utils.list_xenstore_macaddrs') as mac: mac.return_value = ['BC764E206C5B'] with mock.patch('novaagent.utils.list_hw_interfaces') as hwint: hwint.return_value = ['eth1', 'lo'] mock_response = mock.Mock() mock_response.side_effect = [ 'BC764E206C5B', None ] with mock.patch( 'novaagent.utils.get_hw_addr', side_effect=mock_response ): with mock.patch( 'novaagent.utils.get_interface' ) as inter: inter.return_value = ( xen_data.check_network_interface() ) with mock.patch( 'novaagent.utils.get_ifcfg_files_to_remove' ) as ifcfg_files: ifcfg_files.return_value = ['/tmp/ifcfg-eth1'] mock_popen = mock.Mock() mock_comm = mock.Mock() mock_comm.return_value = ('out', 'error') mock_popen.side_effect = [ mock.Mock( returncode=1, communicate=mock_comm ), mock.Mock( returncode=0, communicate=mock_comm ) ] with mock.patch( 'novaagent.libs.centos.Popen', side_effect=mock_popen ): result = temp.resetnetwork( 'name', 'value', 'dummy_client' ) self.assertEqual( result, ('0', ''), 'Result was not the expected value' ) network_files = glob.glob('/tmp/network*') self.assertEqual( len(network_files), 2, 'Incorrect number of network files' ) ifcfg_files = glob.glob('/tmp/ifcfg-eth*') self.assertEqual( len(ifcfg_files), 2, 'Incorrect number of ifcfg files' ) route_files = glob.glob('/tmp/route*') self.assertEqual( len(route_files), 2, 'Incorrect number of route files' ) localhost = glob.glob('/tmp/ifcfg-lo') self.assertEqual( len(localhost), 1, 'Localhost ifcfg file was moved out of the way and should not have' ) def test_reset_network_success(self): self.setup_temp_route() self.setup_temp_interface_config('eth1') self.setup_temp_interface_config('lo') self.setup_temp_network() temp = centos.ServerOS() temp.netconfig_dir = '/tmp' temp.network_file = '/tmp/network' with mock.patch( 'novaagent.libs.centos.ServerOS._setup_hostname' ) as hostname: hostname.return_value = 0, 'test_hostname' with mock.patch('novaagent.utils.list_xenstore_macaddrs') as mac: mac.return_value = ['BC764E206C5B'] with mock.patch('novaagent.utils.list_hw_interfaces') as hwint: hwint.return_value = ['eth1', 'lo'] mock_response = mock.Mock() mock_response.side_effect = [ 'BC764E206C5B', None ] with mock.patch( 'novaagent.utils.get_hw_addr', side_effect=mock_response ): with mock.patch( 'novaagent.utils.get_interface' ) as inter: inter.return_value = ( xen_data.check_network_interface() ) with mock.patch( 'novaagent.utils.get_ifcfg_files_to_remove' ) as ifcfg_files: ifcfg_files.return_value = ['/tmp/ifcfg-eth1'] with mock.patch( 'novaagent.libs.centos.Popen' ) as p: p.return_value.communicate.return_value = ( 'out', 'error' ) p.return_value.returncode = 0 result = temp.resetnetwork( 'name', 'value', 'dummy_client' ) self.assertEqual( result, ('0', ''), 'Result was not the expected value' ) network_files = glob.glob('/tmp/network*') self.assertEqual( len(network_files), 2, 'Incorrect number of network files' ) ifcfg_files = glob.glob('/tmp/ifcfg-eth*') self.assertEqual( len(ifcfg_files), 2, 'Incorrect number of ifcfg files' ) route_files = glob.glob('/tmp/route*') self.assertEqual( len(route_files), 2, 'Incorrect number of route files' ) localhost = glob.glob('/tmp/ifcfg-lo') self.assertEqual( len(localhost), 1, 'Localhost ifcfg file was moved out of the way and should not have' ) def test_reset_network_error(self): self.setup_temp_route() self.setup_temp_interface_config('eth1') self.setup_temp_interface_config('lo') self.setup_temp_network() temp = centos.ServerOS() temp.netconfig_dir = '/tmp' temp.network_file = '/tmp/network' with mock.patch( 'novaagent.libs.centos.ServerOS._setup_hostname' ) as hostname: hostname.return_value = 0, 'test_hostname' with mock.patch('novaagent.utils.list_xenstore_macaddrs') as mac: mac.return_value = ['BC764E206C5B'] with mock.patch('novaagent.utils.list_hw_interfaces') as hwint: hwint.return_value = ['eth1'] with mock.patch('novaagent.utils.get_hw_addr') as addr: addr.return_value = 'BC764E206C5B' with mock.patch( 'novaagent.utils.get_interface' ) as inter: inter.return_value = ( xen_data.check_network_interface() ) with mock.patch( 'novaagent.utils.get_ifcfg_files_to_remove' ) as ifcfg_files: ifcfg_files.return_value = ['/tmp/ifcfg-eth1'] with mock.patch( 'novaagent.libs.centos.Popen' ) as p: p.return_value.communicate.return_value = ( 'out', 'error' ) p.return_value.returncode = 1 result = temp.resetnetwork( 'name', 'value', 'dummy_client' ) self.assertEqual( result, ('1', 'Error restarting network'), 'Result was not the expected value' ) network_files = glob.glob('/tmp/network*') self.assertEqual( len(network_files), 2, 'Incorrect number of network files' ) ifcfg_files = glob.glob('/tmp/ifcfg-eth*') self.assertEqual( len(ifcfg_files), 2, 'Incorrect number of ifcfg files' ) route_files = glob.glob('/tmp/route*') self.assertEqual( len(route_files), 2, 'Incorrect number of route files' ) localhost = glob.glob('/tmp/ifcfg-lo') self.assertEqual( len(localhost), 1, 'Localhost ifcfg file was moved out of the way and should not have' ) def test_reset_network_success_systemctl(self): self.setup_temp_route() self.setup_temp_interface_config('eth1') self.setup_temp_interface_config('lo') self.setup_temp_network() temp = centos.ServerOS() temp.netconfig_dir = '/tmp' temp.network_file = '/tmp/network' mock_response = mock.Mock() mock_response.side_effect = [ True, True, False, True, True ] with mock.patch( 'novaagent.libs.centos.os.path.exists', mock_response ): with mock.patch( 'novaagent.libs.centos.ServerOS._setup_hostname' ) as hostname: hostname.return_value = 0, 'test_hostname' with mock.patch( 'novaagent.utils.list_xenstore_macaddrs' ) as mac: mac.return_value = ['BC764E206C5B'] with mock.patch( 'novaagent.utils.list_hw_interfaces' ) as hwint: hwint.return_value = ['eth1'] with mock.patch( 'novaagent.utils.get_hw_addr' ) as hw_addr: hw_addr.return_value = 'BC764E206C5B' with mock.patch( 'novaagent.utils.get_interface' ) as inter: inter.return_value = ( xen_data.check_network_interface() ) with mock.patch( 'novaagent.utils.get_ifcfg_files_to_remove' ) as ifcfg_files: ifcfg_files.return_value = [ '/tmp/ifcfg-eth1' ] with mock.patch( 'novaagent.libs.centos.Popen' ) as p: p.return_value.communicate.return_value = ('out', 'error') # noqa p.return_value.returncode = 0 result = temp.resetnetwork( 'name', 'value', 'dummy_client' ) self.assertEqual( result, ('0', ''), 'Result was not the expected value' ) network_files = glob.glob('/tmp/network*') self.assertEqual( len(network_files), 2, 'Incorrect number of network files' ) ifcfg_files = glob.glob('/tmp/ifcfg-eth*') self.assertEqual( len(ifcfg_files), 2, 'Incorrect number of ifcfg files' ) route_files = glob.glob('/tmp/route*') self.assertEqual( len(route_files), 2, 'Incorrect number of route files' ) localhost = glob.glob('/tmp/ifcfg-lo') self.assertEqual( len(localhost), 1, 'Localhost ifcfg file was moved out of the way and should not have' ) def test_reset_network_error_systemctl(self): self.setup_temp_route() self.setup_temp_interface_config('eth1') self.setup_temp_interface_config('lo') self.setup_temp_network() temp = centos.ServerOS() temp.netconfig_dir = '/tmp' temp.network_file = '/tmp/network' mock_response = mock.Mock() mock_response.side_effect = [ True, True, False, True, True ] with mock.patch( 'novaagent.libs.centos.os.path.exists', mock_response ): with mock.patch( 'novaagent.libs.centos.ServerOS._setup_hostname' ) as hostname: hostname.return_value = 0, 'test_hostname' with mock.patch( 'novaagent.utils.list_xenstore_macaddrs' ) as mac: mac.return_value = ['BC764E206C5B'] with mock.patch( 'novaagent.utils.list_hw_interfaces' ) as hwint: hwint.return_value = ['eth1'] with mock.patch( 'novaagent.utils.get_hw_addr' ) as hw_addr: hw_addr.return_value = 'BC764E206C5B' with mock.patch( 'novaagent.utils.get_interface' ) as inter: inter.return_value = ( xen_data.check_network_interface() ) with mock.patch( 'novaagent.utils.get_ifcfg_files_to_remove' ) as ifcfg_files: ifcfg_files.return_value = [ '/tmp/ifcfg-eth1' ] with mock.patch( 'novaagent.libs.centos.Popen' ) as p: p.return_value.communicate.return_value = ('out', 'error') # noqa p.return_value.returncode = 1 result = temp.resetnetwork( 'name', 'value', 'dummy_client' ) self.assertEqual( result, ('1', 'Error restarting network'), 'Result was not the expected value' ) network_files = glob.glob('/tmp/network*') self.assertEqual( len(network_files), 2, 'Incorrect number of network files' ) ifcfg_files = glob.glob('/tmp/ifcfg-eth*') self.assertEqual( len(ifcfg_files), 2, 'Incorrect number of ifcfg files' ) route_files = glob.glob('/tmp/route*') self.assertEqual( len(route_files), 2, 'Incorrect number of route files' ) localhost = glob.glob('/tmp/ifcfg-lo') self.assertEqual( len(localhost), 1, 'Localhost ifcfg file was moved out of the way and should not have' ) def test_setup_routes(self): self.setup_temp_route() temp = centos.ServerOS() temp.netconfig_dir = '/tmp' temp_iface = xen_data.check_network_interface() temp._setup_routes('eth1', temp_iface) files = glob.glob('/tmp/route-eth1*') self.assertEqual( len(files), 2, 'Did not find correct number of files' ) with open('/tmp/route-eth1') as f: written_data = f.readlines() for index, line in enumerate(written_data): self.assertEqual( line, network.CENTOS_ROUTE_FILE[index], 'Written file did not match expected value' ) def test_setup_interfaces_eth0(self): self.setup_temp_interface_config('eth0') temp = centos.ServerOS() temp.netconfig_dir = '/tmp' temp_iface = network.ETH0_INTERFACE temp._setup_interface('eth0', temp_iface) files = glob.glob('/tmp/ifcfg-eth0*') self.assertEqual( len(files), 2, 'Did not find correct number of files' ) with open('/tmp/ifcfg-eth0') as f: written_data = f.readlines() for index, line in enumerate(written_data): self.assertEqual( line, network.CENTOS_IFCFG_ETH0[index], 'Written file did not match expected value' ) def test_setup_interfaces_eth1(self): self.setup_temp_interface_config('eth1') temp = centos.ServerOS() temp.netconfig_dir = '/tmp' temp_iface = xen_data.check_network_interface() temp._setup_interface('eth1', temp_iface) files = glob.glob('/tmp/ifcfg-eth1*') self.assertEqual( len(files), 2, 'Did not find correct number of files' ) with open('/tmp/ifcfg-eth1') as f: written_data = f.readlines() for index, line in enumerate(written_data): self.assertEqual( line, network.CENTOS_IFCFG_ETH1[index], 'Written file did not match expected value' ) def test_setup_hostname_hostname_success(self): self.setup_temp_hostname() temp = centos.ServerOS() temp.hostname_file = '/tmp/hostname' test_hostname = 'test.hostname' with mock.patch('novaagent.utils.get_hostname') as hostname: hostname.return_value = test_hostname with mock.patch('novaagent.libs.centos.os.path.exists') as exists: exists.return_value = False with mock.patch('novaagent.libs.centos.Popen') as popen: popen.return_value.communicate.return_value = ( ('out', 'err') ) popen.return_value.returncode = 0 return_code, hostname = temp._setup_hostname( 'dummy_client' ) self.assertEqual( hostname, test_hostname, 'Did not receive expected host from function' ) self.assertEqual( return_code, 0, 'Return code received was not expected value' ) def test_setup_hostname_hostname_failure(self): self.setup_temp_hostname() temp = centos.ServerOS() temp.hostname_file = '/tmp/hostname' test_hostname = 'test.hostname' with mock.patch('novaagent.utils.get_hostname') as hostname: hostname.return_value = test_hostname with mock.patch('novaagent.libs.centos.os.path.exists') as exists: exists.return_value = False with mock.patch('novaagent.libs.centos.Popen') as popen: popen.return_value.communicate.return_value = ( ('out', 'err') ) popen.return_value.returncode = 1 return_code, hostname = temp._setup_hostname( 'dummy_client' ) self.assertEqual( hostname, test_hostname, 'Did not receive expected host from function' ) self.assertEqual( return_code, 1, 'Return code received was not expected value' ) def test_setup_hostname_hostnamectl_success(self): self.setup_temp_hostname() temp = centos.ServerOS() temp.hostname_file = '/tmp/hostname' test_hostname = 'test.hostname' with mock.patch('novaagent.utils.get_hostname') as hostname: hostname.return_value = test_hostname with mock.patch('novaagent.libs.centos.os.path.exists') as exists: exists.return_value = True with mock.patch('novaagent.libs.centos.Popen') as popen: popen.return_value.communicate.return_value = ( ('out', 'err') ) popen.return_value.returncode = 0 return_code, hostname = temp._setup_hostname( 'dummy_client' ) self.assertEqual( hostname, test_hostname, 'Did not receive expected host from function' ) self.assertEqual( return_code, 0, 'Return code received was not expected value' ) def test_setup_hostname_hostnamectl_failure(self): self.setup_temp_hostname() temp = centos.ServerOS() temp.hostname_file = '/tmp/hostname' test_hostname = 'test.hostname' with mock.patch('novaagent.utils.get_hostname') as hostname: hostname.return_value = test_hostname with mock.patch('novaagent.libs.centos.os.path.exists') as exists: exists.return_value = True with mock.patch('novaagent.libs.centos.Popen') as popen: popen.return_value.communicate.return_value = ( ('out', 'err') ) popen.return_value.returncode = 1 return_code, hostname = temp._setup_hostname( 'dummy_client' ) self.assertEqual( hostname, test_hostname, 'Did not receive expected host from function' ) self.assertEqual( return_code, 1, 'Return code received was not expected value' ) nova-agent-2.1.13/tests/tests_libs_debian.py000066400000000000000000000664301325673674100210550ustar00rootroot00000000000000 from novaagent.libs import debian from .fixtures import xen_data from .fixtures import network import logging import glob import copy import sys import os if sys.version_info[:2] >= (2, 7): from unittest import TestCase else: from unittest2 import TestCase try: from unittest import mock except ImportError: import mock class TestHelpers(TestCase): def setUp(self): logging.disable(logging.ERROR) self.time_patcher = mock.patch('novaagent.libs.debian.time.sleep') self.time_patcher.start() def tearDown(self): logging.disable(logging.NOTSET) file_searches = [ '/tmp/hostname*', '/tmp/interfaces*', '/tmp/network*', '/tmp/rackspace-cloud*' ] for search in file_searches: route_files = glob.glob(search) for item in route_files: os.remove(item) self.time_patcher.stop() def setup_temp_hostname(self): with open('/tmp/hostname', 'a+') as f: f.write('This is a test file') def setup_temp_interfaces(self): with open('/tmp/interfaces', 'a+') as f: f.write('#This is a test file\n') def setup_temp_netplan(self): with open('/tmp/rackspace-cloud.yaml', 'a+') as f: f.write('#This is a test file\n') def test_setup_loopback(self): temp = debian.ServerOS() temp.netconfig_file = '/tmp/interfaces' temp._setup_loopback() with open('/tmp/interfaces') as f: written_data = f.readlines() for index, line in enumerate(written_data): self.assertEqual( line, network.DEBIAN_INTERFACES_LOOPBACK[index], 'Written file did not match expected value' ) def test_reset_network_hostname_failure(self): self.setup_temp_hostname() self.setup_temp_interfaces() temp = debian.ServerOS() temp.hostname_file = '/tmp/hostname' temp.netconfig_file = '/tmp/interfaces' with mock.patch( 'novaagent.libs.debian.ServerOS._setup_hostname' ) as hostname: hostname.return_value = 1 with mock.patch('novaagent.utils.list_xenstore_macaddrs') as mac: mac.return_value = ['BC764E207572', 'BC764E206C5B'] with mock.patch('novaagent.utils.list_hw_interfaces') as hwint: hwint.return_value = ['eth0', 'eth1'] mock_hw_address = mock.Mock() mock_hw_address.side_effect = [ 'BC764E207572', 'BC764E206C5B' ] with mock.patch( 'novaagent.utils.get_hw_addr', side_effect=mock_hw_address ): mock_interface = mock.Mock() mock_interface.side_effect = [ network.ETH0_INTERFACE, xen_data.check_network_interface() ] with mock.patch( 'novaagent.utils.get_interface', side_effect=mock_interface ): mock_popen = mock.Mock() mock_comm = mock.Mock() mock_comm.return_value = ('out', 'error') mock_popen.side_effect = [ mock.Mock(returncode=0, communicate=mock_comm), mock.Mock(returncode=0, communicate=mock_comm), mock.Mock(returncode=0, communicate=mock_comm), mock.Mock(returncode=0, communicate=mock_comm), mock.Mock(returncode=0, communicate=mock_comm), mock.Mock(returncode=0, communicate=mock_comm) ] with mock.patch( 'novaagent.libs.debian.Popen', side_effect=mock_popen ): result = temp.resetnetwork( 'name', 'value', 'dummy_client' ) self.assertEqual( result, ('0', ''), 'Result was not the expected value' ) interface_files = glob.glob('/tmp/interfaces*') self.assertEqual( len(interface_files), 2, 'Incorrect number of interface files' ) with open('/tmp/interfaces') as f: written_data = f.readlines() update_config = copy.deepcopy(network.DEBIAN_INTERFACES_CONFIG) del update_config[0] loopback = [ '# The loopback network interface\n', 'auto lo\n', 'iface lo inet loopback\n', '\n' ] check_success = loopback + update_config for index, line in enumerate(written_data): self.assertIn( line, check_success, 'Written file did not match expected value' ) def test_reset_network_error_down(self): self.setup_temp_hostname() self.setup_temp_interfaces() temp = debian.ServerOS() temp.hostname_file = '/tmp/hostname' temp.netconfig_file = '/tmp/interfaces' with mock.patch( 'novaagent.libs.debian.ServerOS._setup_hostname' ) as hostname: hostname.return_value = 0, 'test_hostname' with mock.patch('novaagent.utils.list_xenstore_macaddrs') as mac: mac.return_value = ['BC764E206C5B'] with mock.patch('novaagent.utils.list_hw_interfaces') as hwint: hwint.return_value = ['eth1'] mock_hw_address = mock.Mock() mock_hw_address.side_effect = [ 'BC764E206C5B' ] with mock.patch( 'novaagent.utils.get_hw_addr', side_effect=mock_hw_address ): mock_interface = mock.Mock() mock_interface.side_effect = [ xen_data.check_network_interface() ] with mock.patch( 'novaagent.utils.get_interface', side_effect=mock_interface ): with mock.patch( 'novaagent.libs.debian.Popen' ) as p: p.return_value.communicate.return_value = ( 'out', 'error' ) p.return_value.returncode = 1 result = temp.resetnetwork( 'name', 'value', 'dummy_client' ) self.assertEqual( result, ('1', 'Error stopping network: eth1'), 'Result was not the expected value' ) interface_files = glob.glob('/tmp/interfaces*') self.assertEqual( len(interface_files), 2, 'Incorrect number of interface files' ) def test_reset_network_error_flush(self): self.setup_temp_hostname() self.setup_temp_interfaces() temp = debian.ServerOS() temp.hostname_file = '/tmp/hostname' temp.netconfig_file = '/tmp/interfaces' with mock.patch( 'novaagent.libs.debian.ServerOS._setup_hostname' ) as hostname: hostname.return_value = 0, 'test_hostname' with mock.patch('novaagent.utils.list_xenstore_macaddrs') as mac: mac.return_value = ['BC764E206C5B'] with mock.patch('novaagent.utils.list_hw_interfaces') as hwint: hwint.return_value = ['eth1'] mock_hw_address = mock.Mock() mock_hw_address.side_effect = [ 'BC764E206C5B' ] with mock.patch( 'novaagent.utils.get_hw_addr', side_effect=mock_hw_address ): mock_interface = mock.Mock() mock_interface.side_effect = [ xen_data.check_network_interface() ] with mock.patch( 'novaagent.utils.get_interface', side_effect=mock_interface ): mock_popen = mock.Mock() mock_comm = mock.Mock() mock_comm.return_value = ('out', 'error') mock_popen.side_effect = [ mock.Mock(returncode=0, communicate=mock_comm), mock.Mock(returncode=1, communicate=mock_comm) ] with mock.patch( 'novaagent.libs.debian.Popen', side_effect=mock_popen ): result = temp.resetnetwork( 'name', 'value', 'dummy_client' ) self.assertEqual( result, ('1', 'Error flushing network: eth1'), 'Result was not the expected value' ) interface_files = glob.glob('/tmp/interfaces*') self.assertEqual( len(interface_files), 2, 'Incorrect number of interface files' ) def test_reset_network_error_up(self): self.setup_temp_hostname() self.setup_temp_interfaces() temp = debian.ServerOS() temp.hostname_file = '/tmp/hostname' temp.netconfig_file = '/tmp/interfaces' with mock.patch( 'novaagent.libs.debian.ServerOS._setup_hostname' ) as hostname: hostname.return_value = 0, 'test_hostname' with mock.patch('novaagent.utils.list_xenstore_macaddrs') as mac: mac.return_value = ['BC764E206C5B'] with mock.patch('novaagent.utils.list_hw_interfaces') as hwint: hwint.return_value = ['eth1'] mock_hw_address = mock.Mock() mock_hw_address.side_effect = [ 'BC764E206C5B' ] with mock.patch( 'novaagent.utils.get_hw_addr', side_effect=mock_hw_address ): mock_interface = mock.Mock() mock_interface.side_effect = [ xen_data.check_network_interface() ] with mock.patch( 'novaagent.utils.get_interface', side_effect=mock_interface ): mock_popen = mock.Mock() mock_comm = mock.Mock() mock_comm.return_value = ('out', 'error') mock_popen.side_effect = [ mock.Mock(returncode=0, communicate=mock_comm), mock.Mock(returncode=0, communicate=mock_comm), mock.Mock(returncode=1, communicate=mock_comm) ] with mock.patch( 'novaagent.libs.debian.Popen', side_effect=mock_popen ): result = temp.resetnetwork( 'name', 'value', 'dummy_client' ) self.assertEqual( result, ('1', 'Error starting network: eth1'), 'Result was not the expected value' ) interface_files = glob.glob('/tmp/interfaces*') self.assertEqual( len(interface_files), 2, 'Incorrect number of interface files' ) def test_reset_network_success(self): self.setup_temp_hostname() self.setup_temp_interfaces() temp = debian.ServerOS() temp.hostname_file = '/tmp/hostname' temp.netconfig_file = '/tmp/interfaces' with mock.patch( 'novaagent.libs.debian.ServerOS._setup_hostname' ) as hostname: hostname.return_value = 0 with mock.patch('novaagent.utils.list_xenstore_macaddrs') as mac: mac.return_value = ['BC764E207572', 'BC764E206C5B'] with mock.patch('novaagent.utils.list_hw_interfaces') as hwint: hwint.return_value = ['eth0', 'eth1'] mock_hw_address = mock.Mock() mock_hw_address.side_effect = [ 'BC764E207572', 'BC764E206C5B' ] with mock.patch( 'novaagent.utils.get_hw_addr', side_effect=mock_hw_address ): mock_interface = mock.Mock() mock_interface.side_effect = [ network.ETH0_INTERFACE, xen_data.check_network_interface() ] with mock.patch( 'novaagent.utils.get_interface', side_effect=mock_interface ): mock_popen = mock.Mock() mock_comm = mock.Mock() mock_comm.return_value = ('out', 'error') mock_popen.side_effect = [ mock.Mock(returncode=0, communicate=mock_comm), mock.Mock(returncode=0, communicate=mock_comm), mock.Mock(returncode=0, communicate=mock_comm), mock.Mock(returncode=0, communicate=mock_comm), mock.Mock(returncode=0, communicate=mock_comm), mock.Mock(returncode=0, communicate=mock_comm) ] with mock.patch( 'novaagent.libs.debian.Popen', side_effect=mock_popen ): result = temp.resetnetwork( 'name', 'value', 'dummy_client' ) self.assertEqual( result, ('0', ''), 'Result was not the expected value' ) interface_files = glob.glob('/tmp/interfaces*') self.assertEqual( len(interface_files), 2, 'Incorrect number of interface files' ) with open('/tmp/interfaces') as f: written_data = f.readlines() update_config = copy.deepcopy(network.DEBIAN_INTERFACES_CONFIG) del update_config[0] loopback = [ '# The loopback network interface\n', 'auto lo\n', 'iface lo inet loopback\n', '\n' ] check_success = loopback + update_config for index, line in enumerate(written_data): self.assertIn( line, check_success, 'Written file did not match expected value' ) def test_interface_setup(self): self.setup_temp_interfaces() temp = debian.ServerOS() temp.netconfig_file = '/tmp/interfaces' temp_iface = network.ETH0_INTERFACE temp._setup_interfaces('eth0', temp_iface) temp_iface = xen_data.check_network_interface() temp._setup_interfaces('eth1', temp_iface) files = glob.glob('/tmp/interfaces*') self.assertEqual( len(files), 1, 'Did not find correct number of files' ) with open('/tmp/interfaces') as f: written_data = f.readlines() for index, line in enumerate(written_data): self.assertEqual( line, network.DEBIAN_INTERFACES_CONFIG[index], 'Written file did not match expected value' ) def test_netplan_setup(self): self.setup_temp_netplan() temp = debian.ServerOS() temp.netplan_file = '/tmp/rackspace-cloud.yaml' temp._setup_netplan(network.ALL_INTERFACES) files = glob.glob('/tmp/rackspace-cloud*') self.assertEqual( len(files), 1, 'Did not find correct number of files' ) with open('/tmp/rackspace-cloud.yaml') as f: written_data = f.readlines() for index, line in enumerate(written_data): self.assertEqual( line, network.UBUNTU_NETPLAN_CONFIG[index], 'Written file did not match expected value' ) def test_reset_network_netplan_success(self): self.setup_temp_hostname() self.setup_temp_netplan() temp = debian.ServerOS() temp.hostname_file = '/tmp/hostname' temp.netplan_file = '/tmp/rackspace-cloud.yaml' with mock.patch( 'novaagent.libs.debian.ServerOS._setup_hostname' ) as hostname: hostname.return_value = 0 with mock.patch('novaagent.utils.list_xenstore_macaddrs') as mac: mac.return_value = ['BC764E207572', 'BC764E206C5B'] with mock.patch('novaagent.utils.list_hw_interfaces') as hwint: hwint.return_value = ['eth0', 'eth1'] mock_hw_address = mock.Mock() mock_hw_address.side_effect = [ 'BC764E207572', 'BC764E206C5B' ] with mock.patch( 'novaagent.utils.get_hw_addr', side_effect=mock_hw_address ): mock_interface = mock.Mock() mock_interface.side_effect = [ network.ETH0_INTERFACE, xen_data.check_network_interface() ] with mock.patch( 'novaagent.utils.get_interface', side_effect=mock_interface ): with mock.patch( 'novaagent.libs.debian.os.path.exists' ) as exists: exists.return_value = True mock_popen = mock.Mock() mock_comm = mock.Mock() mock_comm.return_value = ('out', 'error') mock_popen.side_effect = [ mock.Mock( returncode=0, communicate=mock_comm ) ] with mock.patch( 'novaagent.libs.debian.Popen', side_effect=mock_popen ): result = temp.resetnetwork( 'name', 'value', 'dummy_client' ) self.assertEqual( result, ('0', ''), 'Result was not the expected value' ) netplan_files = glob.glob('/tmp/rackspace-cloud*') self.assertEqual( len(netplan_files), 2, 'Incorrect number of rackspace yaml files' ) with open('/tmp/rackspace-cloud.yaml') as f: written_data = f.readlines() for index, line in enumerate(written_data): self.assertEqual( line, network.DEBIAN_NETPLAN_CONFIG[index], 'Written file did not match expected value' ) def test_reset_network_netplan_failure(self): self.setup_temp_hostname() self.setup_temp_netplan() temp = debian.ServerOS() temp.hostname_file = '/tmp/hostname' temp.netplan_file = '/tmp/rackspace-cloud.yaml' with mock.patch( 'novaagent.libs.debian.ServerOS._setup_hostname' ) as hostname: hostname.return_value = 0 with mock.patch('novaagent.utils.list_xenstore_macaddrs') as mac: mac.return_value = ['BC764E207572', 'BC764E206C5B'] with mock.patch('novaagent.utils.list_hw_interfaces') as hwint: hwint.return_value = ['eth0', 'eth1'] mock_hw_address = mock.Mock() mock_hw_address.side_effect = [ 'BC764E207572', 'BC764E206C5B' ] with mock.patch( 'novaagent.utils.get_hw_addr', side_effect=mock_hw_address ): mock_interface = mock.Mock() mock_interface.side_effect = [ network.ETH0_INTERFACE, xen_data.check_network_interface() ] with mock.patch( 'novaagent.utils.get_interface', side_effect=mock_interface ): with mock.patch( 'novaagent.libs.debian.os.path.exists' ) as exists: exists.return_value = True with mock.patch( 'novaagent.libs.debian.Popen' ) as p: p.return_value.communicate.return_value = ( 'out', 'error' ) p.return_value.returncode = 1 result = temp.resetnetwork( 'name', 'value', 'dummy_client' ) self.assertEqual( result, ('1', 'Error applying netplan: error'), 'Result was not the expected value' ) netplan_files = glob.glob('/tmp/rackspace-cloud*') self.assertEqual( len(netplan_files), 2, 'Incorrect number of rackspace yaml files' ) def test_setup_hostname_hostname_success(self): self.setup_temp_hostname() temp = debian.ServerOS() temp.hostname_file = '/tmp/hostname' test_hostname = 'test.hostname' with mock.patch('novaagent.utils.get_hostname') as hostname: hostname.return_value = test_hostname with mock.patch('novaagent.libs.debian.os.path.exists') as exists: exists.return_value = False with mock.patch('novaagent.libs.debian.Popen') as popen: popen.return_value.communicate.return_value = ( ('out', 'err') ) popen.return_value.returncode = 0 return_code = temp._setup_hostname( 'dummy_client' ) self.assertEqual( return_code, 0, 'Return code received was not expected value' ) def test_setup_hostname_hostname_failure(self): self.setup_temp_hostname() temp = debian.ServerOS() temp.hostname_file = '/tmp/hostname' test_hostname = 'test.hostname' with mock.patch('novaagent.utils.get_hostname') as hostname: hostname.return_value = test_hostname with mock.patch('novaagent.libs.debian.os.path.exists') as exists: exists.return_value = False with mock.patch('novaagent.libs.debian.Popen') as popen: popen.return_value.communicate.return_value = ( ('out', 'err') ) popen.return_value.returncode = 1 return_code = temp._setup_hostname( 'dummy_client' ) self.assertEqual( return_code, 1, 'Return code received was not expected value' ) def test_setup_hostname_hostnamectl_success(self): self.setup_temp_hostname() temp = debian.ServerOS() temp.hostname_file = '/tmp/hostname' test_hostname = 'test.hostname' with mock.patch('novaagent.utils.get_hostname') as hostname: hostname.return_value = test_hostname with mock.patch('novaagent.libs.debian.os.path.exists') as exists: exists.return_value = True with mock.patch('novaagent.libs.debian.Popen') as popen: popen.return_value.communicate.return_value = ( ('out', 'err') ) popen.return_value.returncode = 0 return_code = temp._setup_hostname( 'dummy_client' ) self.assertEqual( return_code, 0, 'Return code received was not expected value' ) def test_setup_hostname_hostnamectl_and_hostname_failure(self): self.setup_temp_hostname() temp = debian.ServerOS() temp.hostname_file = '/tmp/hostname' test_hostname = 'test.hostname' with mock.patch('novaagent.utils.get_hostname') as hostname: hostname.return_value = test_hostname with mock.patch('novaagent.libs.debian.os.path.exists') as exists: exists.return_value = True with mock.patch('novaagent.libs.debian.Popen') as popen: popen.return_value.communicate.return_value = ( ('out', 'err') ) popen.return_value.returncode = 1 return_code = temp._setup_hostname( 'dummy_client' ) self.assertEqual( return_code, 1, 'Return code received was not expected value' ) nova-agent-2.1.13/tests/tests_libs_redhat.py000066400000000000000000000014231325673674100210710ustar00rootroot00000000000000 from novaagent.libs import redhat import logging import sys if sys.version_info[:2] >= (2, 7): from unittest import TestCase else: from unittest2 import TestCase try: from unittest import mock except ImportError: import mock class TestHelpers(TestCase): def setUp(self): logging.disable(logging.ERROR) def tearDown(self): logging.disable(logging.NOTSET) def test_redhat_kmsactivate(self): temp = redhat.ServerOS() with mock.patch('novaagent.common.kms.kms_activate') as kms: kms.return_value = ("0", "") message = temp.kmsactivate('name', 'value', 'client') self.assertEqual( ("0", ""), message, 'Return value was not what was expected' ) nova-agent-2.1.13/tests/tests_novaagent.py000066400000000000000000000315101325673674100205730ustar00rootroot00000000000000 from novaagent.libs import centos import novaagent import logging import time import sys import os if sys.version_info[:2] >= (2, 7): from unittest import TestCase else: from unittest2 import TestCase try: from unittest import mock except ImportError: import mock class TestHelpers(TestCase): def setUp(self): logging.disable(logging.ERROR) self.time_patcher = mock.patch('novaagent.novaagent.time.sleep') self.time_patcher.start() def tearDown(self): logging.disable(logging.NOTSET) if os.path.exists('/tmp/log'): os.remove('/tmp/log') self.time_patcher.stop() def test_xen_action_no_action(self): temp_os = centos.ServerOS() test_xen_event = { "name": "bad_key", "value": "68436575764933852815830951574296" } with mock.patch('novaagent.utils.list_xen_events') as xen_list: xen_list.return_value = ['748dee41-c47f-4ec7-b2cd-037e51da4031'] with mock.patch('novaagent.utils.get_xen_event') as xen_event: xen_event.return_value = test_xen_event with mock.patch( 'novaagent.utils.remove_xenhost_event' ) as remove: remove.return_value = True with mock.patch( 'novaagent.utils.update_xenguest_event' ) as update: update.return_value = True try: novaagent.novaagent.action(temp_os, 'dummy_client') except Exception: assert False, ( 'An exception was thrown during action' ) def test_xen_action_action_success(self): temp_os = centos.ServerOS() test_xen_event = { "name": "keyinit", "value": "68436575764933852815830951574296" } with mock.patch('novaagent.utils.list_xen_events') as xen_list: xen_list.return_value = ['748dee41-c47f-4ec7-b2cd-037e51da4031'] with mock.patch('novaagent.utils.get_xen_event') as xen_event: xen_event.return_value = test_xen_event with mock.patch('novaagent.libs.DefaultOS.keyinit') as keyinit: keyinit.return_value = ('D0', 'SECRET_STRING') with mock.patch( 'novaagent.utils.remove_xenhost_event' ) as remove: remove.return_value = True with mock.patch( 'novaagent.utils.update_xenguest_event' ) as update: update.return_value = True try: novaagent.novaagent.action( temp_os, 'dummy_client' ) except Exception: assert False, ( 'An exception was thrown during action' ) def test_main_success(self): class Test(object): def __init__(self): self.logfile = '/tmp/log' self.loglevel = 'info' self.no_fork = False test_args = Test() mock_response = mock.Mock() mock_response.side_effect = [ time.sleep(1), time.sleep(1), KeyboardInterrupt ] with mock.patch( 'novaagent.novaagent.argparse.ArgumentParser.parse_args' ) as parse_args: parse_args.return_value = test_args with mock.patch( 'novaagent.novaagent.get_server_type' ) as server_type: server_type.return_value = centos with mock.patch('novaagent.novaagent.os.fork') as fork: fork.return_value = 20 with mock.patch('novaagent.novaagent.os._exit'): with mock.patch('novaagent.novaagent.action'): with mock.patch( 'novaagent.novaagent.os.path.exists' ) as exists: exists.return_value = False with mock.patch( 'novaagent.novaagent.check_provider' ): with mock.patch( 'novaagent.novaagent.time.sleep', side_effect=mock_response ): try: novaagent.novaagent.main() except KeyboardInterrupt: pass except Exception: assert False, ( 'An exception was thrown' ) def test_main_success_no_fork(self): class Test(object): def __init__(self): self.logfile = '-' self.loglevel = 'info' self.no_fork = True test_args = Test() mock_response = mock.Mock() mock_response.side_effect = [ time.sleep(1), time.sleep(1), KeyboardInterrupt ] with mock.patch( 'novaagent.novaagent.argparse.ArgumentParser.parse_args' ) as parse_args: parse_args.return_value = test_args with mock.patch( 'novaagent.novaagent.get_server_type' ) as server_type: server_type.return_value = centos with mock.patch('novaagent.novaagent.action'): with mock.patch( 'novaagent.novaagent.os.path.exists' ) as exists: exists.return_value = False with mock.patch( 'novaagent.novaagent.check_provider' ): with mock.patch( 'novaagent.novaagent.time.sleep', side_effect=mock_response ): try: novaagent.novaagent.main() except KeyboardInterrupt: pass except Exception: assert False, ( 'An unknown exception was thrown' ) def test_main_success_with_xenbus(self): class Test(object): def __init__(self): self.logfile = '-' self.loglevel = 'info' self.no_fork = False test_args = Test() mock_response = mock.Mock() mock_response.side_effect = [ time.sleep(1), time.sleep(1), KeyboardInterrupt ] with mock.patch( 'novaagent.novaagent.argparse.ArgumentParser.parse_args' ) as parse_args: parse_args.return_value = test_args with mock.patch( 'novaagent.novaagent.get_server_type' ) as server_type: server_type.return_value = centos with mock.patch('novaagent.novaagent.os.fork') as fork: fork.return_value = 20 with mock.patch('novaagent.novaagent.os._exit'): with mock.patch( 'novaagent.novaagent.os.path.exists' ) as exists: exists.return_value = True with mock.patch('novaagent.novaagent.Client'): with mock.patch( 'novaagent.novaagent.check_provider' ): with mock.patch( 'novaagent.novaagent.action' ): with mock.patch( 'novaagent.novaagent.time.sleep', side_effect=mock_response ): try: novaagent.novaagent.main() except KeyboardInterrupt: pass except Exception: assert False, ( 'An unknown exception' 'was thrown' ) def test_main_os_error(self): class Test(object): def __init__(self): self.logfile = '-' self.loglevel = 'info' self.no_fork = False test_args = Test() mock_response = mock.Mock() mock_response.side_effect = [ True, True, KeyboardInterrupt ] with mock.patch( 'novaagent.novaagent.argparse.ArgumentParser.parse_args' ) as parse_args: parse_args.return_value = test_args with mock.patch( 'novaagent.novaagent.get_server_type' ) as server_type: server_type.return_value = centos with mock.patch('novaagent.novaagent.os.fork') as fork: fork.side_effect = OSError with mock.patch( 'novaagent.novaagent.os._exit', side_effect=OSError ): try: novaagent.novaagent.main() except OSError: pass except Exception: assert False, ( 'An unknown exception has been thrown on start' ) finally: return def test_server_type_debian(self): mock_response = mock.Mock() mock_response.side_effect = [ False, False, False, True ] with mock.patch( 'novaagent.novaagent.os.path.exists', side_effect=mock_response ): server_type = novaagent.novaagent.get_server_type() self.assertEqual( server_type.__name__, 'novaagent.libs.debian', 'Did not get expected object for debian' ) def test_server_type_redhat(self): mock_response = mock.Mock() mock_response.side_effect = [ False, False, True ] with mock.patch( 'novaagent.novaagent.os.path.exists', side_effect=mock_response ): server_type = novaagent.novaagent.get_server_type() self.assertEqual( server_type.__name__, 'novaagent.libs.redhat', 'Did not get expected object for redhat' ) def test_server_type_centos(self): mock_response = mock.Mock() mock_response.side_effect = [ False, True ] with mock.patch( 'novaagent.novaagent.os.path.exists', side_effect=mock_response ): server_type = novaagent.novaagent.get_server_type() self.assertEqual( server_type.__name__, 'novaagent.libs.centos', 'Did not get expected object for centos' ) def test_provider_failure(self): try: with mock.patch( 'novaagent.novaagent.os._exit', side_effect=sys.exit ): novaagent.novaagent.check_provider('billy_bobs_computers') except SystemExit: pass except Exception: assert False, 'Exit was not called when it should have been' def test_provider_success(self): try: with mock.patch( 'novaagent.novaagent.os._exit', side_effect=sys.exit ): novaagent.novaagent.check_provider('RacKSpaCe') except SystemExit: assert False, 'A system exit happened and should not have' except Exception: assert False, 'A general exception happened and should not have' nova-agent-2.1.13/tests/tests_utils.py000066400000000000000000000637671325673674100177740ustar00rootroot00000000000000 from .fixtures import utils_data from .fixtures import xen_data from novaagent import utils import logging import glob import sys import os if sys.version_info[:2] >= (2, 7): from unittest import TestCase else: from unittest2 import TestCase try: from unittest import mock except ImportError: import mock class ClientTest(object): """ Test class used for client mock """ def __init__(self, return_value): self.return_data = return_value def list(self, path): return self.return_data def read(self, path): return self.return_data def write(self, event, data): return self.return_data def delete(self, path): return self.return_data class TestHelpers(TestCase): def setUp(self): logging.disable(logging.ERROR) if not os.path.exists('/tmp/ifcfg-eth0'): with open('/tmp/ifcfg-eth0', 'a+') as f: f.write('This is a test file') os.utime('/tmp/ifcfg-eth0', None) def tearDown(self): logging.disable(logging.NOTSET) files = glob.glob('/tmp/ifcfg-eth0*') for item in files: os.remove(item) def test_get_hostname_success(self): client = ClientTest(xen_data.get_hostname(True)) hostname = utils.get_hostname(client) self.assertEqual( hostname, 'test-server', 'Hostname does not match expected ouput' ) def test_get_hostname_success_socket(self): with mock.patch( 'novaagent.utils.xenstore.xenstore_read', side_effect=ValueError ): with mock.patch('novaagent.utils.socket') as get: get.gethostname.return_value = ( xen_data.get_hostname(False) ) hostname = utils.get_hostname('dummy_client') self.assertEqual( hostname, 'test-server', 'Hostname does not match expected ouput' ) def test_get_hostname_success_popen(self): with mock.patch('novaagent.xenstore.xenstore.Popen') as popen: popen.return_value.communicate.return_value = ( utils_data.get_hostname(True) ) popen.return_value.returncode = 0 hostname = utils.get_hostname(None) self.assertEqual( hostname, 'test-server', 'Hostname does not match expected ouput' ) def test_get_hostname_failure_popen(self): with mock.patch('novaagent.xenstore.xenstore.Popen') as popen: popen.return_value.communicate.return_value = (b'', '') popen.return_value.returncode = 1 with mock.patch('novaagent.utils.socket') as get: get.gethostname.return_value = ( utils_data.get_hostname(False) ) hostname = utils.get_hostname(None) self.assertEqual( hostname, 'test-server', 'Hostname does not match expected ouput' ) def test_get_hostname_exception_popen(self): with mock.patch( 'novaagent.xenstore.xenstore.Popen', side_effect=ValueError ): with mock.patch('novaagent.utils.socket') as get: get.gethostname.return_value = ( utils_data.get_hostname(False) ) hostname = utils.get_hostname(None) self.assertEqual( hostname, 'test-server', 'Hostname does not match expected ouput' ) def test_list_host_xen_events(self): check_events = ['748dee41-c47f-4ec7-b2cd-037e51da4031'] client = ClientTest(xen_data.get_xen_host_events()) event_list = utils.list_xen_events(client) self.assertEqual( event_list, check_events, 'Event list does not match expected list' ) def test_list_host_xen_events_exception(self): client = ClientTest(None) event_list = utils.list_xen_events(client) self.assertEqual( event_list, [], 'Event list should be an empty list with exception' ) def test_list_host_xen_events_popen(self): check_events = ['748dee41-c47f-4ec7-b2cd-037e51da4031'] with mock.patch('novaagent.xenstore.xenstore.Popen') as popen: popen.return_value.communicate.return_value = ( utils_data.get_xen_host_events() ) popen.return_value.returncode = 0 event_list = utils.list_xen_events(None) self.assertEqual( event_list, check_events, 'Event list does not match expected list' ) def test_list_host_xen_events_failure_popen(self): with mock.patch('novaagent.xenstore.xenstore.Popen') as popen: popen.return_value.communicate.return_value = (b'', '') popen.return_value.returncode = 1 event_list = utils.list_xen_events(None) self.assertEqual( event_list, [], 'Event list does not match expected list after failure' ) def test_list_host_xen_events_popen_exception(self): with mock.patch( 'novaagent.xenstore.xenstore.Popen', side_effect=ValueError ): event_list = utils.list_xen_events(None) self.assertEqual( event_list, [], 'Event list should be an empty list with exception' ) def test_get_host_event(self): host_event_id = '748dee41-c47f-4ec7-b2cd-037e51da4031' event_check = { "name": "keyinit", "value": "68436575764933852815830951574296" } client = ClientTest(xen_data.get_xen_host_event_details()) event_details = utils.get_xen_event(host_event_id, client) self.assertEqual( event_check, event_details, 'Event details do not match expected value' ) def test_get_host_event_exception(self): host_event_id = '748dee41-c47f-4ec7-b2cd-037e51da4031' client = ClientTest(None) event_details = utils.get_xen_event(host_event_id, client) self.assertEqual( event_details, None, 'Event details should be None on exception' ) def test_get_host_event_popen(self): host_event_id = '748dee41-c47f-4ec7-b2cd-037e51da4031' event_check = { "name": "keyinit", "value": "68436575764933852815830951574296" } with mock.patch('novaagent.xenstore.xenstore.Popen') as popen: popen.return_value.communicate.return_value = ( utils_data.get_xen_host_event_details() ) popen.return_value.returncode = 0 event_details = utils.get_xen_event(host_event_id, None) self.assertEqual( event_check, event_details, 'Event details do not match expected value' ) def test_get_host_event_failure_popen(self): host_event_id = '748dee41-c47f-4ec7-b2cd-037e51da4031' with mock.patch('novaagent.xenstore.xenstore.Popen') as popen: popen.return_value.communicate.return_value = (b'', '') popen.return_value.returncode = 1 event_details = utils.get_xen_event(host_event_id, None) self.assertEqual( event_details, None, 'Event details do not match expected value after failure' ) def test_get_host_event_popen_exception(self): host_event_id = '748dee41-c47f-4ec7-b2cd-037e51da4031' with mock.patch( 'novaagent.xenstore.xenstore.Popen', side_effect=ValueError ): event_details = utils.get_xen_event(host_event_id, None) self.assertEqual( event_details, None, 'Event details should be None on exception' ) def test_remove_xenhost_event_failure(self): host_event_id = '748dee41-c47f-4ec7-b2cd-037e51da4031' success = utils.remove_xenhost_event(host_event_id, 'dummy_client') self.assertEqual( success, False, 'Return value was not False on failure' ) def test_remove_xenhost_event_success(self): host_event_id = '748dee41-c47f-4ec7-b2cd-037e51da4031' client = ClientTest('') success = utils.remove_xenhost_event(host_event_id, client) self.assertEqual( success, True, 'Return value was not True on success' ) def test_remove_xenhost_event_success_popen(self): host_event_id = '748dee41-c47f-4ec7-b2cd-037e51da4031' with mock.patch('novaagent.xenstore.xenstore.Popen') as popen: popen.return_value.communicate.return_value = (b'', '') popen.return_value.returncode = 0 success = utils.remove_xenhost_event(host_event_id, None) self.assertEqual( success, True, 'Return value was not True on success' ) def test_remove_xenhost_event_failure_popen(self): host_event_id = '748dee41-c47f-4ec7-b2cd-037e51da4031' with mock.patch('novaagent.xenstore.xenstore.Popen') as popen: popen.return_value.communicate.return_value = (b'', '') popen.return_value.returncode = 1 success = utils.remove_xenhost_event(host_event_id, None) self.assertEqual( success, False, 'Return value was not False on failure' ) def test_remove_xenhost_event_exception_popen(self): host_event_id = '748dee41-c47f-4ec7-b2cd-037e51da4031' with mock.patch( 'novaagent.xenstore.xenstore.Popen', side_effect=ValueError ): success = utils.remove_xenhost_event(host_event_id, None) self.assertEqual( success, False, 'Return value was not False on exception' ) def test_write_xenguest_event_success(self): event_uuid = '748dee41-c47f-4ec7-b2cd-037e51da4031' client = ClientTest('') write_data = {"message": "", "returncode": "0"} success = utils.update_xenguest_event(event_uuid, write_data, client) self.assertEqual( success, True, 'Return value was not True on success' ) def test_write_xenguest_event_failure(self): event_uuid = '748dee41-c47f-4ec7-b2cd-037e51da4031' write_data = {"message": "", "returncode": "0"} success = utils.update_xenguest_event( event_uuid, write_data, 'dummy_client' ) self.assertEqual( success, False, 'Return value was not False on failure' ) def test_write_xenguest_event_success_popen(self): event_uuid = '748dee41-c47f-4ec7-b2cd-037e51da4031' write_data = {"message": "", "returncode": "0"} with mock.patch('novaagent.xenstore.xenstore.Popen') as popen: popen.return_value.communicate.return_value = (b'', '') popen.return_value.returncode = 0 success = utils.update_xenguest_event(event_uuid, write_data, None) self.assertEqual( success, True, 'Return value was not True on success' ) def test_write_xenguest_event_failure_popen(self): event_uuid = '748dee41-c47f-4ec7-b2cd-037e51da4031' write_data = {"message": "", "returncode": "0"} with mock.patch('novaagent.xenstore.xenstore.Popen') as popen: popen.return_value.communicate.return_value = (b'', '') popen.return_value.returncode = 1 success = utils.update_xenguest_event(event_uuid, write_data, None) self.assertEqual( success, False, 'Return value was not False on failure' ) def test_write_xenguest_event_exception_popen(self): event_uuid = '748dee41-c47f-4ec7-b2cd-037e51da4031' write_data = {"message": "", "returncode": "0"} with mock.patch( 'novaagent.xenstore.xenstore.Popen', side_effect=ValueError ): success = utils.update_xenguest_event(event_uuid, write_data, None) self.assertEqual( success, False, 'Return value was not False on failure' ) def test_network_get_interfaces_success(self): mac_address = 'BC764E206C5B' client = ClientTest(xen_data.get_network_interface()) network_info = utils.get_interface(mac_address, client) self.assertEqual( network_info, xen_data.check_network_interface(), 'Network info returned was not the expected value' ) def test_network_get_interfaces_failure(self): mac_address = 'BC764E206C5B' client = ClientTest(None) network_info = utils.get_interface(mac_address, client) self.assertEqual( network_info, None, 'Network info should be None on error' ) def test_network_get_interfaces_success_popen(self): mac_address = 'BC764E206C5B' with mock.patch('novaagent.xenstore.xenstore.Popen') as popen: popen.return_value.communicate.return_value = ( utils_data.get_network_interface() ) popen.return_value.returncode = 0 network_info = utils.get_interface(mac_address, None) self.assertEqual( network_info, xen_data.check_network_interface(), 'Network info returned was not the expected value' ) def test_network_get_interfaces_failure_popen(self): mac_address = 'BC764E206C5B' with mock.patch('novaagent.xenstore.xenstore.Popen') as popen: popen.return_value.communicate.return_value = (b'', '') popen.return_value.returncode = 1 network_info = utils.get_interface(mac_address, None) self.assertEqual( network_info, None, 'Network info returned was not the expected value' ) def test_network_get_interfaces_exception_popen(self): mac_address = 'BC764E206C5B' with mock.patch( 'novaagent.xenstore.xenstore.Popen', side_effect=ValueError ): network_info = utils.get_interface(mac_address, None) self.assertEqual( network_info, None, 'Network info returned was not the expected value' ) def test_network_get_provider_success(self): client = ClientTest(b'Test Provider') provider = utils.get_provider(client) self.assertEqual( provider, 'Test Provider', 'Providers do not match expected value' ) def test_network_get_provider_exception(self): client = ClientTest(None) provider = utils.get_provider(client) self.assertEqual( provider, None, 'Provider should have been None' ) def test_network_get_provider_empty(self): client = ClientTest(b'') provider = utils.get_provider(client) self.assertEqual( provider, '', 'Provider should have been an empty string' ) def test_network_get_provider_success_popen(self): with mock.patch('novaagent.xenstore.xenstore.Popen') as popen: popen.return_value.communicate.return_value = ( b'Test Provider', b'' ) popen.return_value.returncode = 0 provider = utils.get_provider(None) self.assertEqual( provider, 'Test Provider', 'Provider does not match expected value' ) def test_network_get_provider_exception_popen(self): with mock.patch( 'novaagent.xenstore.xenstore.Popen', side_effect=ValueError ): provider = utils.get_provider(None) self.assertEqual( provider, None, 'Provider returned should be None' ) def test_network_get_provider_failure_popen(self): with mock.patch('novaagent.xenstore.xenstore.Popen') as popen: popen.return_value.communicate.return_value = (b'', '') popen.return_value.returncode = 1 provider = utils.get_provider(None) self.assertEqual( provider, None, 'Provider returned should be None' ) def test_network_get_mac_addresses_success(self): check_mac_addrs = ['BC764E206C5B', 'BC764E206C5A'] client = ClientTest(xen_data.get_mac_addresses()) mac_addrs = utils.list_xenstore_macaddrs(client) self.assertEqual( mac_addrs, check_mac_addrs, 'Mac addrs returned do not match expected value' ) def test_network_get_mac_addresses_exception(self): client = ClientTest(None) mac_addrs = utils.list_xenstore_macaddrs(client) self.assertEqual( mac_addrs, [], 'Mac addrs returned is not empty list after error' ) def test_network_get_mac_addresses_failure(self): client = ClientTest([]) mac_addrs = utils.list_xenstore_macaddrs(client) self.assertEqual( mac_addrs, [], 'Mac addrs returned is not empty list after error' ) def test_network_get_mac_addresses_success_popen(self): check_mac_addrs = ['BC764E206C5B', 'BC764E206C5A'] with mock.patch('novaagent.xenstore.xenstore.Popen') as popen: popen.return_value.communicate.return_value = ( utils_data.get_mac_addresses() ) popen.return_value.returncode = 0 mac_addrs = utils.list_xenstore_macaddrs(None) self.assertEqual( mac_addrs, check_mac_addrs, 'Mac addrs returned do not match expected value' ) def test_network_get_mac_addresses_exception_popen(self): with mock.patch( 'novaagent.xenstore.xenstore.Popen', side_effect=ValueError ): mac_addrs = utils.list_xenstore_macaddrs(None) self.assertEqual( mac_addrs, [], 'Mac addrs returned is not empty list after popen exception' ) def test_network_get_mac_addresses_failure_popen(self): with mock.patch('novaagent.xenstore.xenstore.Popen') as popen: popen.return_value.communicate.return_value = (b'', '') popen.return_value.returncode = 1 mac_addrs = utils.list_xenstore_macaddrs(None) self.assertEqual( mac_addrs, [], 'Mac addrs returned is not empty list after popen error' ) def test_get_os_interfaces(self): interfaces = ['lo', 'eth1', 'eth0'] with mock.patch('novaagent.utils.os.path.exists') as os_path: os_path.return_value = True with mock.patch('novaagent.utils.os.listdir') as list_dir: list_dir.return_value = interfaces list_interfaces = utils.list_hw_interfaces() self.assertEqual( interfaces, list_interfaces, 'Interfaces returned do not match expected return' ) def test_get_os_interfaces_netifaces(self): interfaces = ['lo', 'eth1', 'eth0'] with mock.patch('novaagent.utils.os.path.exists') as os_path: os_path.return_value = False with mock.patch('novaagent.utils.netifaces.interfaces') as netif: netif.return_value = interfaces list_interfaces = utils.list_hw_interfaces() self.assertEqual( interfaces, list_interfaces, 'Interfaces returned do not match expected return' ) def test_get_mac_address_from_system_string(self): check_mac_addr = 'BC764E2012B3' with mock.patch('novaagent.utils.socket.socket.fileno') as fileno: fileno.return_value = 3 with mock.patch('novaagent.utils.fcntl.ioctl') as get_hex: get_hex.return_value = xen_data.FNCTL_INFO_STRING mac_address = utils.get_hw_addr('eth1') self.assertEqual( check_mac_addr, mac_address, 'Mac addresses returned does not match expected value' ) def test_get_mac_address_from_system_bytes(self): check_mac_addr = 'BC764E2012B3' with mock.patch('novaagent.utils.socket.socket.fileno') as fileno: fileno.return_value = 3 with mock.patch('novaagent.utils.fcntl.ioctl') as get_hex: get_hex.return_value = xen_data.FCNTL_INFO_BYTES mac_address = utils.get_hw_addr('eth1') self.assertEqual( check_mac_addr, mac_address, 'Mac addresses returned does not match expected value' ) def test_get_mac_address_from_system_error(self): with mock.patch('novaagent.utils.socket.socket.fileno') as fileno: fileno.return_value = 3 with mock.patch('novaagent.utils.fcntl.ioctl') as get_hex: get_hex.side_effect = IOError utils.HAS_NETIFACES = False mac_address = utils.get_hw_addr('eth1') self.assertEqual( False, mac_address, 'Mac address returned should be false on error' ) def test_get_mac_address_from_system_netifaces(self): check_mac_addr = 'BC764E205A79' with mock.patch('novaagent.utils.socket.socket.fileno') as fileno: fileno.return_value = 3 with mock.patch('novaagent.utils.fcntl.ioctl') as get_hex: get_hex.side_effect = IOError with mock.patch('novaagent.utils.netifaces') as interfaces: interfaces.ifaddresses.return_value = ( xen_data.get_iface_from_netifaces() ) interfaces.AF_LINK = 17 utils.HAS_NETIFACES = True mac_address = utils.get_hw_addr('eth1') self.assertEqual( check_mac_addr, mac_address, 'Mac addresses returned does not match expected value' ) def test_get_mac_address_from_system_netifaces_failure(self): with mock.patch('novaagent.utils.socket.socket.fileno') as fileno: fileno.return_value = 3 with mock.patch('novaagent.utils.fcntl.ioctl') as get_hex: get_hex.side_effect = IOError with mock.patch('novaagent.utils.netifaces') as interfaces: interfaces.ifaddresses.return_value = ( xen_data.get_iface_from_netifaces() ) interfaces.AF_LINK = 99 utils.HAS_NETIFACES = True mac_address = utils.get_hw_addr('eth1') self.assertEqual( False, mac_address, 'Mac addresses returned should be false on error' ) def test_netmask_to_prefix_24(self): cidr = utils.netmask_to_prefix('255.255.255.0') self.assertEqual( cidr, 24, 'Cidr returned does not match expected value' ) cidr = utils.netmask_to_prefix('255.255.0.0') self.assertEqual( cidr, 16, 'Cidr returned does not match expected value' ) def test_network_remove_files(self): net_config_dir = '/etc/sysconfig/network-scripts' interface_file_prefix = 'ifcfg-' with mock.patch('novaagent.utils.os.listdir') as listdir: listdir.return_value = ['lo', 'eth0'] with mock.patch('novaagent.utils.glob.glob') as files: files.return_value = [ '/etc/sysconfig/network-scripts/ifcfg-eth1', '/etc/sysconfig/network-scripts/ifcfg-lo', '/etc/sysconfig/network-scripts/ifcfg-eth0' ] remove_files = utils.get_ifcfg_files_to_remove( net_config_dir, interface_file_prefix ) self.assertEqual( remove_files, ['/etc/sysconfig/network-scripts/ifcfg-eth1'], 'Remove files returned is not the expected value' ) def test_move_interface_file_for_backup(self): rename_file = '/tmp/ifcfg-eth0' utils.backup_file(rename_file) files = glob.glob('/tmp/ifcfg-eth0.*.*.bak') self.assertEqual( len(files), 1, 'Did not find any files' ) self.assertIn( 'ifcfg-eth0', files[0], 'Did not find the original filename in renamed file path' ) def test_move_interface_file_for_backup_no_file(self): rename_file = '/tmp/ifcfg-eth0' os.remove(rename_file) utils.backup_file(rename_file) assert True, 'Move interface did not generate error' def test_rename_interface_file_success(self): rename_file = '/tmp/ifcfg-eth0' utils.backup_file(rename_file) files = glob.glob('/tmp/ifcfg-eth0.*.*.bak') self.assertEqual( len(files), 1, 'Did not find any files' ) self.assertIn( 'ifcfg-eth0', files[0], 'Did not find the original filename in renamed file path' ) def test_backup_file_failure(self): rename_file = '/tmp/ifcfg-eth0' os.remove(rename_file) utils.backup_file(rename_file) assert True, 'Move interface did not generate error' def test_encoding_to_bytes(self): test_string = 'this is a test' compare_string = b'this is a test' test = utils.encode_to_bytes(test_string) self.assertEqual( compare_string, test, 'Byte strings do not match as expected' ) nova-agent-2.1.13/tests/tests_xenbus.py000066400000000000000000000011411325673674100201120ustar00rootroot00000000000000 from pyxs.client import Client from pyxs.connection import XenBusConnection from novaagent import xenbus import logging import sys if sys.version_info[:2] >= (2, 7): from unittest import TestCase else: from unittest2 import TestCase class TestXenBus(TestCase): def setUp(self): logging.disable(logging.ERROR) def tearDown(self): logging.disable(logging.NOTSET) def test_init(self): c = Client(router=xenbus.XenGuestRouter(XenBusConnection())) assert isinstance(c.router.connection, XenBusConnection) assert not c.router.thread.is_alive()