pax_global_header00006660000000000000000000000064133465162740014525gustar00rootroot0000000000000052 comment=73f7cc50fdd51eeecb9251f5cdfe2d78be25d5a2 nova-agent-2.1.18/000077500000000000000000000000001334651627400136555ustar00rootroot00000000000000nova-agent-2.1.18/.gitignore000066400000000000000000000001371334651627400156460ustar00rootroot00000000000000__pycache__ *.pyc *.swp /build /dist /*.egg-info .coverage .DS_Store coverage.xml .scannerwork nova-agent-2.1.18/.travis.yml000066400000000000000000000002641334651627400157700ustar00rootroot00000000000000 language: python python: - "2.6" - "2.7" - "3.4" - "3.5" - "3.6" - "3.7-dev" install: - pip install -e .[tests] before_script: - flake8 . script: - nosetests -v nova-agent-2.1.18/LICENSE000066400000000000000000000010541334651627400146620ustar00rootroot00000000000000Copyright 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.18/MANIFEST.in000066400000000000000000000000661334651627400154150ustar00rootroot00000000000000graft etc graft debian graft pkgs include LICENSE.txt nova-agent-2.1.18/README.md000066400000000000000000000044261334651627400151420ustar00rootroot00000000000000 [![Travis Status](https://travis-ci.org/Rackspace-DOT/nova-agent.svg?branch=master)](https://travis-ci.org/Rackspace-DOT/nova-agent.svg?branch=master) # Rackspace nova-agent Running agent that helps with the setup of the server initially on first boot, and allows for password and network changes during the life cycle of the server. #### Requirements The agent will check and make sure that the instance is running on Rackspace hosts, and if so it will continue running and complete any tasks that is being requested through xenstore. If it is not then the agent will immediately stop running log the reason. The agent will also look and see if `/dev/xen/xenbus` is available, and if so will utilize [pyxs](https://github.com/selectel/pyxs) library to interact with xenstore. If it is not available then the agent will try and utilize xenstore commands that are provided by xenstore-utils. #### What does the agent do? ##### Networking * RHEL based systems use ifcfg scripts that are located in `/etc/sysconfig/network-scripts` **Note:** If extra options are placed in the ifcfg scripts scripts such as ZONE for firewalld. Then when networking is reset or IP addresses are added/removed those configuration options will be preserved by the agent. * Debian based systems use the `/etc/network/interfaces` file and sets them up accordingly. * Ubuntu based systems that utilize netplan will have networking setup in the following location: `/etc/netplan/rackspace-cloud.yaml` You can learn more about netplan here [https://netplan.io/](https://netplan.io/) and is available on Rackspace cloud in the Ubuntu 18.04 base image. ##### Hostname * On all systems the agent will try and use `hostnamectl` to set the hostname. If that fails then the agent will fall back and use the `hostname` command, and write to the `/etc/hostname` so that the hostname persists through a reboot. ##### Password * Sets the password assigned to the server on initial boot by nova. Also allows for password changes initiated by a user during the life cycle of the server ##### RHEL registration * For RHEL servers the agent completes RHN registration for the server on initial boot #### Compatability The agent is currently python 2.6 - 3.6 compatible, and Travis CI is being utilized for testing all python versions. nova-agent-2.1.18/etc/000077500000000000000000000000001334651627400144305ustar00rootroot00000000000000nova-agent-2.1.18/etc/nova-agent.init000066400000000000000000000024121334651627400173530ustar00rootroot00000000000000#!/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.18/etc/nova-agent.redhat000066400000000000000000000034111334651627400176570ustar00rootroot00000000000000#!/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.18/etc/nova-agent.service000066400000000000000000000004711334651627400200530ustar00rootroot00000000000000[Unit] Description=Nova Agent for xenstore DefaultDependencies=no Wants=cloud-init-local.service Before=network-online.target Before=cloud-init.service [Service] Type=notify TimeoutStartSec=360 ExecStart=/usr/bin/nova-agent --no-fork True -o /var/log/nova-agent.log -l info [Install] WantedBy=multi-user.target nova-agent-2.1.18/etc/nova-agent.upstart000066400000000000000000000003771334651627400201220ustar00rootroot00000000000000description "Nova Agent upstart script" author "Rackspace" start on networking or runlevel [2345] stop on runlevel [!2345] respawn respawn limit 10 5 expect stop umask 022 exec /usr/bin/nova-agent --no-fork True -o /var/log/nova-agent.log -l info nova-agent-2.1.18/novaagent/000077500000000000000000000000001334651627400156375ustar00rootroot00000000000000nova-agent-2.1.18/novaagent/__init__.py000066400000000000000000000000301334651627400177410ustar00rootroot00000000000000 __version__ = '2.1.18' nova-agent-2.1.18/novaagent/common/000077500000000000000000000000001334651627400171275ustar00rootroot00000000000000nova-agent-2.1.18/novaagent/common/__init__.py000066400000000000000000000000001334651627400212260ustar00rootroot00000000000000nova-agent-2.1.18/novaagent/common/file_inject.py000066400000000000000000000062131334651627400217560ustar00rootroot00000000000000# 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 absolute_import 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.18/novaagent/common/kms.py000066400000000000000000000073431334651627400203020ustar00rootroot00000000000000# # 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 """ 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] server_url = ';'.join(['https:%s' % h for h in domains]) no_ssl_server_url = ';'.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=%s; proxyPassword[comment]=The password to use for an authenticated proxy proxyPassword= noSSLServerURL[comment]=None 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 """ % (server_url, no_ssl_server_url) 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: up2date.write(update_files[UP2DATE_PATH]) message = register_with_rhn(activation_key, profile) if message: return message return ("0", "") nova-agent-2.1.18/novaagent/common/password.py000066400000000000000000000140071334651627400213450ustar00rootroot00000000000000# # 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.18/novaagent/libs/000077500000000000000000000000001334651627400165705ustar00rootroot00000000000000nova-agent-2.1.18/novaagent/libs/__init__.py000066400000000000000000000050031334651627400206770ustar00rootroot00000000000000 from __future__ import absolute_import import logging import os from subprocess import PIPE from subprocess import Popen import novaagent from novaagent.common.password import PasswordCommands from novaagent.common.file_inject import FileInject from novaagent import utils log = logging.getLogger(__name__) class DefaultOS(object): def __init__(self): self.hostname_file = '/etc/hostname' 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__)) """ Common function for all operating systems when setting up hostname """ 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 hostnamectl was successful completed = True if not completed: log.debug('Falling back to use hostname command') 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)) else: log.debug('Writing file {0}'.format(self.hostname_file)) with open(self.hostname_file, 'w') as host_file: host_file.write(hostname) return p.returncode, hostname nova-agent-2.1.18/novaagent/libs/centos.py000066400000000000000000000175561334651627400204530ustar00rootroot00000000000000 from __future__ import absolute_import import logging import os import re 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): super(ServerOS, self).__init__() self.netconfig_dir = '/etc/sysconfig/network-scripts' self.network_file = '/etc/sysconfig/network' self.interface_file_prefix = 'ifcfg' self.route_file_prefix = 'route' def _setup_interface(self, ifname, iface): interface_file = '{0}/{1}-{2}'.format( self.netconfig_dir, self.interface_file_prefix, ifname ) # Check and see if there are extra arguments in ifcfg file extra_args = self._check_for_extra_settings(interface_file) # Backup the interface file 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 iface.get('gateway'): iffile.write('GATEWAY={0}\n'.format(iface['gateway'])) if iface.get('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 iface.get('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') if len(extra_args) > 0: for argument in extra_args: iffile.write('{0}\n'.format(argument)) def _check_for_extra_settings(self, interface_file): add_args = [] # The below setting are set in _setup_interface and also ignoring lines # that start with # (comments) and lines with spaces at the beginning known_settings = [ '^BOOTPROTO=', '^DEVICE=', '^GATEWAY=', '^IPV6INIT=', '^IPV6ADDR=', '^IPV6_DEFAULTGW=', '^ONBOOT=', '^NM_CONTROLLED=', '^DNS\d+?=', '^IPADDR\d?', '^NETMASK\d?', '^#', '^\s+' ] log.debug('Checking for additional arguments for ifcfg') pattern = re.compile('|'.join(known_settings)) # File will not exist on initial boot so check and make sure exists if os.path.isfile(interface_file): with open(interface_file, 'r') as file: for line in file: if not pattern.search(line): add_args.append(line.strip()) log.debug( 'Found {0} extra arguments to ' 'add to ifcfg file'.format(len(add_args)) ) return add_args 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 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.18/novaagent/libs/debian.py000066400000000000000000000236101334651627400203660ustar00rootroot00000000000000 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): super(ServerOS, self).__init__() self.netplan_file = '/etc/netplan/rackspace-cloud.yaml' self.netconfig_file = '/etc/network/interfaces' 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_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 iface.get('gateway'): iffile.write( '\tgateway {0}\n'.format( iface['gateway'] ) ) if iface.get('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 iface.get('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} for temp_ip in iface['ips']: temp_net['addresses'].append( '{0}/{1}'.format( temp_ip.get('ip'), utils.netmask_to_prefix(temp_ip.get('netmask')) ) ) if iface.get('gateway'): temp_net['gateway4'] = iface.get('gateway') if iface.get('ip6s'): temp_net['dhcp6'] = False temp_net['gateway6'] = iface.get('gateway_v6') for temp_ipv6 in iface['ip6s']: temp_net['addresses'].append( '{0}/{1}'.format( temp_ipv6.get('ip'), temp_ipv6.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) # Apply the netplan policy 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: # Setup interfaces file self._setup_loopback() for ifname, iface in ifaces.items(): self._setup_interfaces(ifname, iface) # 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.18/novaagent/libs/redhat.py000066400000000000000000000003471334651627400204150ustar00rootroot00000000000000 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.18/novaagent/novaagent.py000066400000000000000000000141411334651627400201740ustar00rootroot00000000000000 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): # Return whether or not to trigger init notification trigger_notify = False xen_events = utils.list_xen_events(client) if len(xen_events) == 0: # if no xen_events then trigger the notification trigger_notify = True for uuid in xen_events: 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 ) ) if event['name'] == 'resetnetwork': # If the network has completed setup then trigger the notification trigger_notify = True return trigger_notify def nova_agent_listen(server_type, server_os, notify, server_init): log.info('Starting actions for {0}'.format(server_type.__name__)) log.info('Checking for existence of /dev/xen/xenbus') send_notification = True notify_init = False 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: notify_init = action(server_os, client=xenbus_client) if send_notification and notify_init: log.info('Sending notification startup is complete') utils.send_notification(server_init, notify) send_notification = False time.sleep(1) else: check_provider(utils.get_provider()) while True: notify_init = action(server_os) if send_notification and notify_init: log.info('Sending notification startup is complete') utils.send_notification(server_init, notify) send_notification = False 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 get_init_system(): # Checking for systemd on OS try: os.stat('/run/systemd/system') log.debug('Systemd is the init system') return 'systemd' except Exception: pass # Check if upstart system was used to start agent upstart_job = os.environ.get('UPSTART_JOB', None) # RHEL 6 and CentOS 6 use rc upstart job to start all the SysVinit # emulation layer instead of individual init scripts if upstart_job not in (None, 'rc'): log.debug('Upstart job that started script: {0}'.format(upstart_job)) return 'upstart' # return None and no notifications to init system will occur log.debug('SysVinit is the init system') return None 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 ) log.info('Agent is starting up') server_type = get_server_type() server_os = server_type.ServerOS() server_init = get_init_system() 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') notify = None if server_init == 'systemd': notify = utils.notify_socket() nova_agent_listen(server_type, server_os, notify, server_init) if __name__ == '__main__': main() nova-agent-2.1.18/novaagent/utils.py000066400000000000000000000156061334651627400173610ustar00rootroot00000000000000 from __future__ import absolute_import from socket import error as socket_error from novaagent.xenstore import xenstore import logging import socket import signal 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 def send_notification(server_init, notify): # Only need to notify systemd and upstart init systems if server_init == 'systemd': systemd_status(*notify, status='', completed=True) elif server_init == 'upstart': os.kill(os.getpid(), signal.SIGSTOP) def notify_socket(): """Return a tuple of address, socket for future use""" _empty = None, None address = os.environ.pop("NOTIFY_SOCKET", None) if not address: return _empty if len(address) == 1: return _empty if address[0] not in ("@", "/"): return _empty if address[0] == "@": address = "\0" + address[1:] sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM) return address, sock def systemd_status(address, sock, status, completed=False): """Helper function to update the service status.""" if completed: message = b"READY=1" else: message = ("STATUS={0}".format(status)).encode('utf8') if not (address and sock and message): return try: sock.sendto(message, address) except socket_error as serr: log.error('Socket error occurred on message send') raise serr return nova-agent-2.1.18/novaagent/xenbus.py000066400000000000000000000034031334651627400175150ustar00rootroot00000000000000 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.18/novaagent/xenstore/000077500000000000000000000000001334651627400175065ustar00rootroot00000000000000nova-agent-2.1.18/novaagent/xenstore/__init__.py000066400000000000000000000000001334651627400216050ustar00rootroot00000000000000nova-agent-2.1.18/novaagent/xenstore/xenstore.py000066400000000000000000000040011334651627400217220ustar00rootroot00000000000000 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.18/run.py000066400000000000000000000001211334651627400150250ustar00rootroot00000000000000from novaagent import novaagent if __name__ == '__main__': novaagent.main() nova-agent-2.1.18/setup.py000066400000000000000000000017671334651627400154020ustar00rootroot00000000000000#!/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.18/tests/000077500000000000000000000000001334651627400150175ustar00rootroot00000000000000nova-agent-2.1.18/tests/__init__.py000066400000000000000000000000001334651627400171160ustar00rootroot00000000000000nova-agent-2.1.18/tests/fixtures/000077500000000000000000000000001334651627400166705ustar00rootroot00000000000000nova-agent-2.1.18/tests/fixtures/__init__.py000066400000000000000000000000001334651627400207670ustar00rootroot00000000000000nova-agent-2.1.18/tests/fixtures/kms_data.py000066400000000000000000000066521334651627400210360ustar00rootroot00000000000000 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.18/tests/fixtures/network.py000066400000000000000000000160151334651627400207360ustar00rootroot00000000000000 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', 'ZONE=TestFirewalldZone\n', 'TEST_OPTION=TEST_VALUE\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', 'ZONE=TestFirewalldZone\n', 'TEST_OPTION=TEST_VALUE\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', ' - 104.130.4.73/24\n', ' - 2001:4802:7802:104:be76:4eff:fe20:7572/64\n', ' - 2001:4802:7802:104:be76:4eff:fe20:7573/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.18/tests/fixtures/utils_data.py000066400000000000000000000025541334651627400214010ustar00rootroot00000000000000 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.18/tests/fixtures/xen_data.py000066400000000000000000000101271334651627400210260ustar00rootroot00000000000000 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.18/tests/tests_common_file_inject.py000066400000000000000000000152301334651627400224370ustar00rootroot00000000000000 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.18/tests/tests_common_kms.py000066400000000000000000000103071334651627400207560ustar00rootroot00000000000000 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.18/tests/tests_common_password.py000066400000000000000000000347171334651627400220410ustar00rootroot00000000000000 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.18/tests/tests_init.py000066400000000000000000000044511334651627400175620ustar00rootroot00000000000000 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.18', '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.18'), '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.18/tests/tests_libs_centos.py000066400000000000000000000760501334651627400211270ustar00rootroot00000000000000 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( 'IPADDR=2.2.2.2\n' 'IPADDR999=1.1.1.1\n' 'ZONE=TestFirewalldZone\n' '# Comment in file\n' ' Starts with a space\n' ' # Mulitple spaces\n' 'TEST_OPTION=TEST_VALUE\n' ) def setup_temp_hostname(self): with open('/tmp/hostname', 'a+') as f: f.write('test.hostname.local') 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, 'temp.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.ServerOS.' '_check_for_extra_settings' ) as check: check.return_value = [] 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_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, 'temp.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.ServerOS.' '_check_for_extra_settings' ) as check: check.return_value = [] 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, 'temp.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.ServerOS.' '_check_for_extra_settings' ) as check: check.return_value = [] 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(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, 'temp.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.ServerOS.' '_check_for_extra_settings' ) as check: check.return_value = [] 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_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, 'temp.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.ServerOS.' '_check_for_extra_settings' ) as check: check.return_value = [] 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, 'temp.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.ServerOS.' '_check_for_extra_settings' ) as check: check.return_value = [] 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_check_extra_args(self): self.setup_temp_interface_config('eth1') temp = centos.ServerOS() interface_file = '/tmp/ifcfg-eth1' extra_args = temp._check_for_extra_settings(interface_file) self.assertEqual( len(extra_args), 2, 'Did not get proper number of arguments from check' ) self.assertEqual( extra_args, ['ZONE=TestFirewalldZone', 'TEST_OPTION=TEST_VALUE'], 'Did not get proper extra arguments from check' ) def test_check_extra_args_no_file(self): temp = centos.ServerOS() interface_file = '/tmp/ifcfg-eth1' extra_args = temp._check_for_extra_settings(interface_file) self.assertEqual( len(extra_args), 0, 'Did not get proper number of arguments from check' ) self.assertEqual( extra_args, [], 'Did not get proper extra arguments from check' ) 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.os.path.exists') as exists: exists.return_value = False with mock.patch('novaagent.libs.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.os.path.exists') as exists: exists.return_value = False with mock.patch('novaagent.libs.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.os.path.exists') as exists: exists.return_value = True with mock.patch('novaagent.libs.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.os.path.exists') as exists: exists.return_value = True with mock.patch('novaagent.libs.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.18/tests/tests_libs_debian.py000066400000000000000000000664121334651627400210570ustar00rootroot00000000000000 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('test.hostname.local') 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_initialization(self): temp = debian.ServerOS() self.assertEqual( temp.netplan_file, '/etc/netplan/rackspace-cloud.yaml', 'Initialized netplan file value does not match expected value' ) self.assertEqual( temp.netconfig_file, '/etc/network/interfaces', 'Initialized netconfig file value does not match expected value' ) self.assertEqual( temp.hostname_file, '/etc/hostname', 'Initialized hostname file value does not match expected value' ) 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, 'temp.hostname' 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, 'temp.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, 'temp.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, 'temp.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, 'temp.hostname' 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, 'temp.hostname' 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, 'temp.hostname' 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.os.path.exists') as exists: exists.return_value = False with mock.patch('novaagent.libs.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' ) with open('/tmp/hostname') as f: written_data = f.readlines() for index, line in enumerate(written_data): self.assertEqual( line, test_hostname, 'Did not find expected hostname in file' ) 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.os.path.exists') as exists: exists.return_value = True with mock.patch('novaagent.libs.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.os.path.exists') as exists: exists.return_value = True with mock.patch('novaagent.libs.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.18/tests/tests_libs_redhat.py000066400000000000000000000014231334651627400210730ustar00rootroot00000000000000 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.18/tests/tests_novaagent.py000066400000000000000000000564001334651627400206020ustar00rootroot00000000000000 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: notify = novaagent.novaagent.action( temp_os, 'dummy_client' ) self.assertEqual( notify, False, 'Unexpected value for notify' ) 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: notify = novaagent.novaagent.action( temp_os, 'dummy_client' ) self.assertEqual( notify, False, 'Notify value should have been False' ) except Exception: assert False, ( 'An exception was thrown during action' ) def test_xen_action_action_success_network(self): temp_os = centos.ServerOS() test_xen_event = { "name": "resetnetwork", "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.centos.ServerOS.resetnetwork' ) as reset: reset.return_value = ('0', '') 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: notify = novaagent.novaagent.action( temp_os, 'dummy_client' ) self.assertEqual( notify, True, 'Notify value should have been True' ) except Exception: assert False, ( 'An exception was thrown during action' ) def test_xen_action_action_no_events(self): temp_os = centos.ServerOS() with mock.patch('novaagent.utils.list_xen_events') as xen_list: xen_list.return_value = [] try: notify = novaagent.novaagent.action( temp_os, 'dummy_client' ) self.assertEqual( notify, True, 'Notify value should have been True' ) 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.get_init_system' ) as init_system: init_system.return_value = None 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.get_init_system' ) as init_system: init_system.return_value = 'None' 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.get_init_system' ) as init_system: init_system.return_value = None 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.get_init_system' ) as init_system: init_system.return_value = None 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_main_success_systemd(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.get_init_system' ) as init_system: init_system.return_value = 'systemd' with mock.patch( 'novaagent.novaagent.get_init_system' ) as notify: notify.return_value = ('test', 'test') with mock.patch( 'novaagent.novaagent.nova_agent_listen' ): try: novaagent.novaagent.main() except KeyboardInterrupt: pass except Exception: assert False, ( 'An unknown exception was thrown' ) 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' def test_get_init_systemd(self): with mock.patch('novaagent.novaagent.os.stat') as stat: stat.return_value = True init_system = novaagent.novaagent.get_init_system() self.assertEqual( init_system, 'systemd', 'Did not get expected init system' ) def test_get_init_upstart(self): with mock.patch('novaagent.novaagent.os.stat', side_effect=ValueError): with mock.patch.dict(os.environ, {'UPSTART_JOB': 'novaagenttest'}): init_system = novaagent.novaagent.get_init_system() self.assertEqual( init_system, 'upstart', 'Did not get expected init system' ) def test_get_init_default(self): with mock.patch('novaagent.novaagent.os.stat', side_effect=ValueError): with mock.patch.dict(os.environ, {}): init_system = novaagent.novaagent.get_init_system() self.assertEqual( init_system, None, 'Did not get expected init system' ) def test_nova_agent_listen_systemd(self): class Test(object): def __init__(self): pass def __name__(self): return 'test' mock_response = mock.Mock() mock_response.side_effect = [ time.sleep(1), time.sleep(1), KeyboardInterrupt ] 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') as action: action.return_value = True with mock.patch( 'novaagent.utils.send_notification' ) as send_notify: with mock.patch( 'novaagent.novaagent.time.sleep', side_effect=mock_response ): try: novaagent.novaagent.nova_agent_listen( Test(), 'centos', 'notify', 'systemd' ) self.assertTrue(send_notify.called) except KeyboardInterrupt: pass except Exception: assert False, ( 'An unknown exception' 'was thrown' ) def test_nova_agent_listen_systemd_multiple_actions(self): class Test(object): def __init__(self): pass def __name__(self): return 'test' mock_response = mock.Mock() mock_response.side_effect = [ time.sleep(1), time.sleep(1), KeyboardInterrupt ] mock_actions = mock.Mock() mock_actions.side_effect = [False, False, True] 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', side_effect=mock_actions ): with mock.patch( 'novaagent.utils.send_notification' ) as send_notify: with mock.patch( 'novaagent.novaagent.time.sleep', side_effect=mock_response ): try: novaagent.novaagent.nova_agent_listen( Test(), 'centos', 'notify', 'systemd' ) except KeyboardInterrupt: pass except Exception: assert False, ( 'An unknown exception' 'was thrown' ) self.assertTrue(send_notify.called) nova-agent-2.1.18/tests/tests_utils.py000066400000000000000000000735311334651627400177640ustar00rootroot00000000000000 from .fixtures import utils_data from .fixtures import xen_data from novaagent import utils from socket import error as socket_error import logging import socket 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' ) def test_notification_systemd(self): with mock.patch('novaagent.utils.systemd_status') as mock_status: try: utils.send_notification('systemd', 'notify') self.assertTrue(mock_status.called) except Exception: assert False, 'systemd notification failed to complete' def test_notification_upstart(self): try: with mock.patch('os.kill') as mock_kill: utils.send_notification('upstart', None) self.assertTrue(mock_kill.called) except Exception: assert False, 'upstart notification failed to complete' def test_notify_empty_address(self): address = None socket = None with mock.patch.dict(os.environ, {'BAD_THINGS': '0'}): bad_address, bad_socket = utils.notify_socket() self.assertEqual( bad_address, address, 'Did not get expected value for address' ) self.assertEqual( bad_socket, socket, 'Did not get expected value for socket' ) def test_notify_bad_length(self): address = None socket = None with mock.patch.dict(os.environ, {'NOTIFY_SOCKET': '1'}): bad_address, bad_socket = utils.notify_socket() self.assertEqual( bad_address, address, 'Did not get expected value for address' ) self.assertEqual( bad_socket, socket, 'Did not get expected value for socket' ) def test_notify_incorrect_starter(self): address = None socket = None with mock.patch.dict(os.environ, {'NOTIFY_SOCKET': '111'}): bad_address, bad_socket = utils.notify_socket() self.assertEqual( bad_address, address, 'Did not get expected value for address' ) self.assertEqual( bad_socket, socket, 'Did not get expected value for socket' ) def test_notify_complete(self): address = '\x00novaagenttest' socket = 'mock_socket' with mock.patch.dict(os.environ, {'NOTIFY_SOCKET': '@novaagenttest'}): with mock.patch( 'novaagent.utils.socket' ) as mock_socket: mock_socket.socket.return_value = 'mock_socket' good_address, good_socket = utils.notify_socket() self.assertEqual( good_address, address, 'Did not get expected value for address' ) self.assertEqual( good_socket, socket, 'Did not get expected value for socket' ) def test_systemd_status_bad_address(self): address = None sock = None status = 'Test' self.assertFalse( utils.systemd_status(address, sock, status), 'Error on empty values' ) def test_systemd_status_completed(self): address = 'address' status = 'Test' mock_socket = mock.Mock() mock_socket.send_to = '' try: utils.systemd_status(address, mock_socket, status, completed=True) except Exception: assert False, 'Exception was caught when should not have' def test_systemd_status_socket_error(self): address = 'address' status = 'Test' try: with mock.patch('novaagent.utils.socket') as test: test.sendto.side_effect = socket.error utils.systemd_status(address, test, status, completed=True) except socket_error: # This is the correct error to raise pass except Exception: assert False, 'Exception was caught when should not have' nova-agent-2.1.18/tests/tests_xenbus.py000066400000000000000000000011411334651627400201140ustar00rootroot00000000000000 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()