summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Pisarski <s.pisarski@cablelabs.com>2018-01-23 16:18:51 +0000
committerGerrit Code Review <gerrit@opnfv.org>2018-01-23 16:18:51 +0000
commit88e9754a4280690acf2ec5942b34336d469673ed (patch)
tree284269828b606e36af90985f579095171cac9aea
parent7cf2a28e78404a3835bfde3516d1fb7ff93aa58d (diff)
parent7ea11eada552627b5385a6a347f23fccee484e67 (diff)
Merge "Added password support for SSH and Ansible Additional protections when initializing network resources Enhanced playbook runner variable support"
-rw-r--r--requirements.txt2
-rw-r--r--snaps/openstack/create_instance.py40
-rw-r--r--snaps/openstack/create_network.py13
-rw-r--r--snaps/openstack/create_router.py10
-rw-r--r--snaps/openstack/utils/launch_utils.py2
-rw-r--r--snaps/openstack/utils/nova_utils.py7
-rw-r--r--snaps/playbook_runner.py45
-rw-r--r--snaps/provisioning/ansible_utils.py46
-rw-r--r--snaps/provisioning/tests/ansible_utils_tests.py15
9 files changed, 127 insertions, 53 deletions
diff --git a/requirements.txt b/requirements.txt
index 137159f..f992fb4 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,7 +1,7 @@
# The order of packages is significant, because pip processes them in the order
# of appearance. Changing the order has an impact on the overall integration
# process, which may cause wedges in the gate later.
-python-novaclient>=9.0.0 # Apache-2.0
+python-novaclient>=9.0.0,<=10 # Apache-2.0
python-neutronclient>=6.3.0 # Apache-2.0
python-keystoneclient>=3.8.0 # Apache-2.0
python-glanceclient>=2.8.0 # Apache-2.0
diff --git a/snaps/openstack/create_instance.py b/snaps/openstack/create_instance.py
index d91e360..631ac6b 100644
--- a/snaps/openstack/create_instance.py
+++ b/snaps/openstack/create_instance.py
@@ -380,7 +380,7 @@ class OpenStackVmInstance(OpenStackComputeObject):
logger.error('Cannot add floating IP [%s]', bre)
raise
except Exception as e:
- logger.debug(
+ logger.warn(
'Retry adding floating IP to instance. Last attempt '
'failed with - %s', e)
time.sleep(poll_interval)
@@ -509,8 +509,9 @@ class OpenStackVmInstance(OpenStackComputeObject):
"""
return ansible_utils.apply_playbook(
pb_file_loc, [self.get_floating_ip(fip_name=fip_name).ip],
- self.get_image_user(), self.keypair_settings.private_filepath,
- variables, self._os_creds.proxy_settings)
+ self.get_image_user(),
+ ssh_priv_key_file_path=self.keypair_settings.private_filepath,
+ variables=variables, proxy_setting=self._os_creds.proxy_settings)
def get_image_user(self):
"""
@@ -619,7 +620,8 @@ class OpenStackVmInstance(OpenStackComputeObject):
status)
return status == expected_status_code
- def vm_ssh_active(self, block=False, poll_interval=POLL_INTERVAL):
+ def vm_ssh_active(self, user_override=None, password=None, block=False,
+ timeout=None, poll_interval=POLL_INTERVAL):
"""
Returns true when the VM can be accessed via SSH
:param block: When true, thread will block until active or timeout
@@ -630,7 +632,8 @@ class OpenStackVmInstance(OpenStackComputeObject):
# sleep and wait for VM status change
logger.info('Checking if VM is active')
- timeout = self.instance_settings.ssh_connect_timeout
+ if not timeout:
+ timeout = self.instance_settings.ssh_connect_timeout
if self.vm_active(block=True):
if block:
@@ -639,7 +642,8 @@ class OpenStackVmInstance(OpenStackComputeObject):
start = time.time() - timeout
while timeout > time.time() - start:
- status = self.__ssh_active()
+ status = self.__ssh_active(
+ user_override=user_override, password=password)
if status:
logger.info('SSH is active for VM instance')
return True
@@ -653,13 +657,14 @@ class OpenStackVmInstance(OpenStackComputeObject):
logger.error('Timeout attempting to connect with VM via SSH')
return False
- def __ssh_active(self):
+ def __ssh_active(self, user_override=None, password=None):
"""
Returns True when can create a SSH session else False
:return: T/F
"""
if len(self.__floating_ip_dict) > 0:
- ssh = self.ssh_client()
+ ssh = self.ssh_client(
+ user_override=user_override, password=password)
if ssh:
ssh.close()
return True
@@ -727,19 +732,32 @@ class OpenStackVmInstance(OpenStackComputeObject):
else:
return self.__get_first_provisioning_floating_ip()
- def ssh_client(self, fip_name=None):
+ def ssh_client(self, fip_name=None, user_override=None, password=None):
"""
Returns an SSH client using the name or the first known floating IP if
exists, else None
:param fip_name: the name of the floating IP to return
+ :param user_override: the username to use instead of the default
+ :param password: the password to use instead of the private key
:return: the SSH client or None
"""
fip = self.get_floating_ip(fip_name)
+
+ ansible_user = self.get_image_user()
+ if user_override:
+ ansible_user = user_override
+
+ if password:
+ private_key = None
+ else:
+ private_key = self.keypair_settings.private_filepath
+
if fip:
return ansible_utils.ssh_client(
self.__get_first_provisioning_floating_ip().ip,
- self.get_image_user(),
- self.keypair_settings.private_filepath,
+ ansible_user,
+ private_key_filepath=private_key,
+ password=password,
proxy_settings=self._os_creds.proxy_settings)
else:
FloatingIPAllocationError(
diff --git a/snaps/openstack/create_network.py b/snaps/openstack/create_network.py
index c9c58e8..984eedd 100644
--- a/snaps/openstack/create_network.py
+++ b/snaps/openstack/create_network.py
@@ -15,7 +15,7 @@
import logging
import enum
-from neutronclient.common.exceptions import NetworkNotFoundClient
+from neutronclient.common.exceptions import NetworkNotFoundClient, Unauthorized
from snaps.config.network import NetworkConfig, SubnetConfig, PortConfig
from snaps.openstack.openstack_creator import OpenStackNetworkObject
@@ -51,9 +51,14 @@ class OpenStackNetwork(OpenStackNetworkObject):
"""
super(self.__class__, self).initialize()
- self.__network = neutron_utils.get_network(
- self._neutron, network_settings=self.network_settings,
- project_id=self.network_settings.get_project_id(self._os_creds))
+ try:
+ self.__network = neutron_utils.get_network(
+ self._neutron, network_settings=self.network_settings,
+ project_id=self.network_settings.get_project_id(
+ self._os_creds))
+ except Unauthorized as e:
+ logger.warn('Unable to lookup network with name %s - %s',
+ self.network_settings.name, e)
return self.__network
diff --git a/snaps/openstack/create_router.py b/snaps/openstack/create_router.py
index 4f95c3b..c9ccdd6 100644
--- a/snaps/openstack/create_router.py
+++ b/snaps/openstack/create_router.py
@@ -14,7 +14,7 @@
# limitations under the License.
import logging
-from neutronclient.common.exceptions import NotFound
+from neutronclient.common.exceptions import NotFound, Unauthorized
from snaps.config.router import RouterConfig
from snaps.openstack.openstack_creator import OpenStackNetworkObject
@@ -61,8 +61,12 @@ class OpenStackRouter(OpenStackNetworkObject):
"""
super(self.__class__, self).initialize()
- self.__router = neutron_utils.get_router(
- self._neutron, router_settings=self.router_settings)
+ try:
+ self.__router = neutron_utils.get_router(
+ self._neutron, router_settings=self.router_settings)
+ except Unauthorized as e:
+ logger.warn('Unable to lookup router with name %s - %s',
+ self.router_settings.name, e)
if self.__router:
for internal_subnet_name in self.router_settings.internal_subnets:
diff --git a/snaps/openstack/utils/launch_utils.py b/snaps/openstack/utils/launch_utils.py
index e10cf48..05d4cb5 100644
--- a/snaps/openstack/utils/launch_utils.py
+++ b/snaps/openstack/utils/launch_utils.py
@@ -462,7 +462,7 @@ def __apply_ansible_playbook(ansible_config, os_creds, vm_dict, image_dict,
retval = ansible_utils.apply_playbook(
ansible_config['playbook_location'], floating_ips, remote_user,
- private_key_filepath,
+ ssh_priv_key_file_path=private_key_filepath,
variables=variables,
proxy_setting=proxy_settings)
if retval != 0:
diff --git a/snaps/openstack/utils/nova_utils.py b/snaps/openstack/utils/nova_utils.py
index e15484c..279e2ec 100644
--- a/snaps/openstack/utils/nova_utils.py
+++ b/snaps/openstack/utils/nova_utils.py
@@ -69,8 +69,11 @@ def create_server(nova, neutron, glance, instance_config, image_config,
ports = list()
for port_setting in instance_config.port_settings:
- ports.append(neutron_utils.get_port(
- neutron, port_settings=port_setting))
+ port = neutron_utils.get_port(neutron, port_settings=port_setting)
+ if port:
+ ports.append(port)
+ else:
+ raise Exception('Cannot find port named - ' + port_setting.name)
nics = []
for port in ports:
kv = dict()
diff --git a/snaps/playbook_runner.py b/snaps/playbook_runner.py
index 87321f5..03b7006 100644
--- a/snaps/playbook_runner.py
+++ b/snaps/playbook_runner.py
@@ -15,9 +15,13 @@
import argparse
import ast
import logging
+import os
import re
+import yaml
+from jinja2 import Environment, FileSystemLoader
+
from snaps.openstack.os_credentials import ProxySettings
from snaps.provisioning import ansible_utils
@@ -41,20 +45,32 @@ def main(parsed_args):
ssh_proxy_cmd=parsed_args.ssh_proxy_cmd)
# Ensure can get an SSH client
- ssh = ansible_utils.ssh_client(parsed_args.ip_addr, parsed_args.host_user,
- parsed_args.priv_key, proxy_settings)
+ ssh = ansible_utils.ssh_client(
+ parsed_args.ip_addr, parsed_args.host_user,
+ private_key_filepath=parsed_args.priv_key,
+ proxy_settings=proxy_settings)
if ssh:
ssh.close()
- vars = dict()
- if args.vars:
- vars = ast.literal_eval(args.vars)
- if not isinstance(vars, dict):
- vars = dict()
+ env = Environment(loader=FileSystemLoader(
+ searchpath=os.path.dirname(parsed_args.env_file)))
+ template = env.get_template(os.path.basename(parsed_args.env_file))
+
+ env_dict = dict()
+ if parsed_args.vars:
+ env_dict = ast.literal_eval(parsed_args.vars)
+
+ output = template.render(**env_dict)
+
+ variables = yaml.load(output)
+
+ if not variables.get('env_file'):
+ variables['env_file'] = parsed_args.env_file
retval = ansible_utils.apply_playbook(
parsed_args.playbook, [parsed_args.ip_addr], parsed_args.host_user,
- parsed_args.priv_key, variables=vars,
+ ssh_priv_key_file_path=parsed_args.priv_key,
+ password=parsed_args.password, variables=variables,
proxy_setting=proxy_settings)
exit(retval)
@@ -63,19 +79,26 @@ if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('-a', '--ip-addr', dest='ip_addr', required=True,
help='The Host IP Address')
- parser.add_argument('-k', '--priv-key', dest='priv_key', required=True,
- help='The location of the private key file')
parser.add_argument('-u', '--host-user', dest='host_user', required=True,
help='Host user account')
+ parser.add_argument('-k', '--priv-key', dest='priv_key', required=False,
+ help='The location of the private key file')
+ parser.add_argument('-pw', '--password', dest='password', required=False,
+ help='The host-user password')
parser.add_argument('-b', '--playbook', dest='playbook', required=True,
help='Playbook Location')
parser.add_argument('-p', '--http-proxy', dest='http_proxy',
required=False, help='<host>:<port>')
parser.add_argument('-s', '--ssh-proxy-cmd', dest='ssh_proxy_cmd',
required=False)
+ parser.add_argument('-e', '--env-file', dest='env_file',
+ help='Yaml file containing playbook substitution vals',
+ required=False)
parser.add_argument('-v', '--vars', dest='vars',
+ help='String renditon of a dict to pass into '
+ 'playbook for additional subtitution values not '
+ 'found in env_file',
required=False)
args = parser.parse_args()
main(args)
-
diff --git a/snaps/provisioning/ansible_utils.py b/snaps/provisioning/ansible_utils.py
index 63f26e1..83fe449 100644
--- a/snaps/provisioning/ansible_utils.py
+++ b/snaps/provisioning/ansible_utils.py
@@ -32,8 +32,9 @@ __author__ = 'spisarski'
logger = logging.getLogger('ansible_utils')
-def apply_playbook(playbook_path, hosts_inv, host_user, ssh_priv_key_file_path,
- variables=None, proxy_setting=None):
+def apply_playbook(playbook_path, hosts_inv, host_user,
+ ssh_priv_key_file_path=None, password=None, variables=None,
+ proxy_setting=None):
"""
Executes an Ansible playbook to the given host
:param playbook_path: the (relative) path to the Ansible playbook
@@ -41,7 +42,10 @@ def apply_playbook(playbook_path, hosts_inv, host_user, ssh_priv_key_file_path,
Ansible playbook
:param host_user: A user for the host instances (must be a password-less
sudo user if playbook has "sudo: yes"
- :param ssh_priv_key_file_path: the file location of the ssh key
+ :param ssh_priv_key_file_path: the file location of the ssh key. Required
+ if password is None
+ :param password: the file location of the ssh key. Required if
+ ssh_priv_key_file_path is None
:param variables: a dictionary containing any substitution variables needed
by the Jinga 2 templates
:param proxy_setting: instance of os_credentials.ProxySettings class
@@ -50,10 +54,20 @@ def apply_playbook(playbook_path, hosts_inv, host_user, ssh_priv_key_file_path,
if not os.path.isfile(playbook_path):
raise AnsibleException('Requested playbook not found - ' + playbook_path)
- pk_file_path = os.path.expanduser(ssh_priv_key_file_path)
- if not os.path.isfile(pk_file_path):
- raise AnsibleException('Requested private SSH key not found - ' +
- pk_file_path)
+ pk_file_path = None
+ if ssh_priv_key_file_path:
+ pk_file_path = os.path.expanduser(ssh_priv_key_file_path)
+ if not password:
+ if not os.path.isfile(pk_file_path):
+ raise AnsibleException('Requested private SSH key not found - ' +
+ pk_file_path)
+
+ if not ssh_priv_key_file_path and not password:
+ raise AnsibleException('Invalid credentials, no priv key or password')
+
+ passwords = None
+ if password:
+ passwords = {'conn_pass': password, 'become_pass': password}
import ansible.constants
ansible.constants.HOST_KEY_CHECKING = False
@@ -93,18 +107,20 @@ def apply_playbook(playbook_path, hosts_inv, host_user, ssh_priv_key_file_path,
variable_manager=variable_manager,
loader=loader,
options=ansible_opts,
- passwords=None)
+ passwords=passwords)
logger.debug('Executing Ansible Playbook - ' + playbook_path)
return executor.run()
-def ssh_client(ip, user, private_key_filepath, proxy_settings=None):
+def ssh_client(ip, user, private_key_filepath=None, password=None,
+ proxy_settings=None):
"""
Retrieves and attemts an SSH connection
:param ip: the IP of the host to connect
:param user: the user with which to connect
- :param private_key_filepath: the path to the private key file
+ :param private_key_filepath: when None, password is required
+ :param password: when None, private_key_filepath is required
:param proxy_settings: instance of os_credentials.ProxySettings class
(optional)
:return: the SSH client if can connect else false
@@ -120,9 +136,13 @@ def ssh_client(ip, user, private_key_filepath, proxy_settings=None):
proxy_cmd_str = proxy_cmd_str.replace("%p", '22')
proxy_cmd = paramiko.ProxyCommand(proxy_cmd_str)
- pk_abs_path = os.path.expanduser(private_key_filepath)
- ssh.connect(ip, username=user, key_filename=pk_abs_path,
- sock=proxy_cmd)
+ pk_abs_path = None
+ if not password and private_key_filepath:
+ pk_abs_path = os.path.expanduser(private_key_filepath)
+
+ ssh.connect(
+ ip, username=user, key_filename=pk_abs_path, password=password,
+ sock=proxy_cmd)
return ssh
except Exception as e:
logger.warning('Unable to connect via SSH with message - ' + str(e))
diff --git a/snaps/provisioning/tests/ansible_utils_tests.py b/snaps/provisioning/tests/ansible_utils_tests.py
index 7600002..851dd64 100644
--- a/snaps/provisioning/tests/ansible_utils_tests.py
+++ b/snaps/provisioning/tests/ansible_utils_tests.py
@@ -266,8 +266,9 @@ class AnsibleProvisioningTests(OSIntegrationTestCase):
retval = self.inst_creator.apply_ansible_playbook(relative_pb_path)
self.assertEqual(0, retval)
- ssh = ansible_utils.ssh_client(ip, user, priv_key,
- self.os_creds.proxy_settings)
+ ssh = ansible_utils.ssh_client(
+ ip, user, private_key_filepath=priv_key,
+ proxy_settings=self.os_creds.proxy_settings)
self.assertIsNotNone(ssh)
scp = None
try:
@@ -329,13 +330,13 @@ class AnsibleProvisioningTests(OSIntegrationTestCase):
relative_pb_path = pkg_resources.resource_filename(
'snaps.provisioning.tests.playbooks',
'template_playbook.yml')
- retval = self.inst_creator.apply_ansible_playbook(relative_pb_path,
- variables={
- 'name': 'Foo'})
+ retval = self.inst_creator.apply_ansible_playbook(
+ relative_pb_path, variables={'name': 'Foo'})
self.assertEqual(0, retval)
- ssh = ansible_utils.ssh_client(ip, user, priv_key,
- self.os_creds.proxy_settings)
+ ssh = ansible_utils.ssh_client(
+ ip, user, private_key_filepath=priv_key,
+ proxy_settings=self.os_creds.proxy_settings)
self.assertIsNotNone(ssh)
scp = None