From 4acf58e758321ff2a2396487cd1abcc14044d933 Mon Sep 17 00:00:00 2001 From: rallytime Date: Mon, 18 May 2015 13:44:08 -0600 Subject: [PATCH 1/5] Switch digital ocean tests to v2 driver This has been done on develop, but this handles the cloud test failures for 2015.5. --- .../cloud/providers/digital_ocean.py | 121 ++++++++++++------ .../conf/cloud.providers.d/digital_ocean.conf | 3 +- 2 files changed, 85 insertions(+), 39 deletions(-) diff --git a/tests/integration/cloud/providers/digital_ocean.py b/tests/integration/cloud/providers/digital_ocean.py index 274015aa97..c77f43fd1a 100644 --- a/tests/integration/cloud/providers/digital_ocean.py +++ b/tests/integration/cloud/providers/digital_ocean.py @@ -1,9 +1,10 @@ # -*- coding: utf-8 -*- ''' - :codeauthor: :email:`Nicole Thomas ` +Integration tests for DigitalOcean APIv2 ''' # Import Python Libs +from __future__ import absolute_import import os import random import string @@ -17,6 +18,9 @@ ensure_in_syspath('../../../') import integration from salt.config import cloud_providers_config +# Import 3rd-party libs +from salt.ext.six.moves import range # pylint: disable=import-error,redefined-builtin + def __random_name(size=6): ''' @@ -32,6 +36,7 @@ INSTANCE_NAME = __random_name() PROVIDER_NAME = 'digital_ocean' + class DigitalOceanTest(integration.ShellCase): ''' Integration tests for the DigitalOcean cloud provider in Salt-Cloud @@ -54,21 +59,23 @@ class DigitalOceanTest(integration.ShellCase): .format(PROVIDER_NAME) ) - # check if client_key, api_key, ssh_key_file, and ssh_key_name are present - path = os.path.join(integration.FILES, - 'conf', - 'cloud.providers.d', - PROVIDER_NAME + '.conf') - config = cloud_providers_config(path) + # check if personal access token, ssh_key_file, and ssh_key_names are present + config = cloud_providers_config( + os.path.join( + integration.FILES, + 'conf', + 'cloud.providers.d', + PROVIDER_NAME + '.conf' + ) + ) - api = config[profile_str][PROVIDER_NAME]['api_key'] - client = config[profile_str][PROVIDER_NAME]['client_key'] + personal_token = config[profile_str][PROVIDER_NAME]['personal_access_token'] ssh_file = config[profile_str][PROVIDER_NAME]['ssh_key_file'] ssh_name = config[profile_str][PROVIDER_NAME]['ssh_key_name'] - if api == '' or client == '' or ssh_file == '' or ssh_name == '': + if personal_token == '' or ssh_file == '' or ssh_name == '': self.skipTest( - 'A client key, an api key, an ssh key file, and an ssh key name ' + 'A personal access token, an ssh key file, and an ssh key name ' 'must be provided to run these tests. Check ' 'tests/integration/files/conf/cloud.providers.d/{0}.conf' .format(PROVIDER_NAME) @@ -78,61 +85,101 @@ class DigitalOceanTest(integration.ShellCase): ''' Tests the return of running the --list-images command for digital ocean ''' - image_name = '14.10 x64' - ret_str = ' {0}'.format(image_name) - list_images = self.run_cloud('--list-images {0}'.format(PROVIDER_NAME)) - self.assertIn(ret_str, list_images) + image_list = self.run_cloud('--list-images {0}'.format(PROVIDER_NAME)) + + self.assertIn( + '14.10 x64', + [i.strip() for i in image_list] + ) def test_list_locations(self): ''' Tests the return of running the --list-locations command for digital ocean ''' - location_name = 'San Francisco 1' - ret_str = ' {0}'.format(location_name) - list_locations = self.run_cloud('--list-locations {0}'.format(PROVIDER_NAME)) - self.assertIn(ret_str, list_locations) + _list_locations = self.run_cloud('--list-locations {0}'.format(PROVIDER_NAME)) + + self.assertIn( + 'San Francisco 1', + [i.strip() for i in _list_locations] + ) def test_list_sizes(self): ''' Tests the return of running the --list-sizes command for digital ocean ''' - size_name = '16GB' - ret_str = ' {0}'.format(size_name) - list_sizes = self.run_cloud('--list-sizes {0}'.format(PROVIDER_NAME)) - self.assertIn(ret_str, list_sizes) + _list_size = self.run_cloud('--list-sizes {0}'.format(PROVIDER_NAME)) + + self.assertIn( + '16gb', + [i.strip() for i in _list_size] + ) + + def test_key_management(self): + ''' + Test key management + ''' + pub = 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAQQDDHr/jh2Jy4yALcK4JyWbVkPRaWmhck3IgCoeOO3z1e2dBowLh64QAM+Qb72pxekALga2oi4GvT+TlWNhzPH4V example' + finger_print = '3b:16:bf:e4:8b:00:8b:b8:59:8c:a9:d3:f0:19:45:fa' + + _key = self.run_cloud('-f create_key {0} name="MyPubKey" public_key="{1}"'.format(PROVIDER_NAME, pub)) + + # Upload public key + self.assertIn( + finger_print, + [i.strip() for i in _key] + ) + + try: + # List all keys + list_keypairs = self.run_cloud('-f list_keypairs {0}'.format(PROVIDER_NAME)) + + self.assertIn( + finger_print, + [i.strip() for i in list_keypairs] + ) + + # List key + show_keypair = self.run_cloud('-f show_keypair {0} keyname={1}'.format(PROVIDER_NAME, 'MyPubKey')) + + self.assertIn( + finger_print, + [i.strip() for i in show_keypair] + ) + except AssertionError: + # Delete the public key if the above assertions fail + self.run_cloud('-f remove_key {0} id={1}'.format(PROVIDER_NAME, finger_print)) + raise + + # Delete public key + self.assertTrue(self.run_cloud('-f remove_key {0} id={1}'.format(PROVIDER_NAME, finger_print))) def test_instance(self): ''' Test creating an instance on DigitalOcean ''' - - # create the instance - instance = self.run_cloud('-p digitalocean-test {0}'.format(INSTANCE_NAME)) - ret_str = ' {0}'.format(INSTANCE_NAME) - # check if instance with salt installed returned try: - self.assertIn(ret_str, instance) + self.assertIn( + INSTANCE_NAME, + [i.strip() for i in self.run_cloud('-p digitalocean-test {0}'.format(INSTANCE_NAME))] + ) except AssertionError: self.run_cloud('-d {0} --assume-yes'.format(INSTANCE_NAME)) raise # delete the instance - delete = self.run_cloud('-d {0} --assume-yes'.format(INSTANCE_NAME)) - ret_str = ' OK' try: - self.assertIn(ret_str, delete) + self.assertIn( + 'True', + [i.strip() for i in self.run_cloud('-d {0} --assume-yes'.format(INSTANCE_NAME))] + ) except AssertionError: raise # Final clean-up of created instance, in case something went wrong. # This was originally in a tearDown function, but that didn't make sense # To run this for each test when not all tests create instances. - query = self.run_cloud('--query') - ret_str = ' {0}:'.format(INSTANCE_NAME) - - # if test instance is still present, delete it - if ret_str in query: + if INSTANCE_NAME in [i.strip() for i in self.run_cloud('--query')]: self.run_cloud('-d {0} --assume-yes'.format(INSTANCE_NAME)) diff --git a/tests/integration/files/conf/cloud.providers.d/digital_ocean.conf b/tests/integration/files/conf/cloud.providers.d/digital_ocean.conf index 20f910c502..9382abfbf6 100644 --- a/tests/integration/files/conf/cloud.providers.d/digital_ocean.conf +++ b/tests/integration/files/conf/cloud.providers.d/digital_ocean.conf @@ -1,7 +1,6 @@ digitalocean-config: provider: digital_ocean - client_key: '' - api_key: '' + personal_access_token: '' ssh_key_file: '' ssh_key_name: '' location: New York 1 From 4a94b2c17ba015144e05a55d693a6d34ee42db0e Mon Sep 17 00:00:00 2001 From: Daniel Wallace Date: Sun, 17 May 2015 23:26:48 -0500 Subject: [PATCH 2/5] add refresh_beacons and sync_beacons This allows them to be used in the gitfs too in /srv/salt/_beacons --- salt/modules/saltutil.py | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/salt/modules/saltutil.py b/salt/modules/saltutil.py index cd39b2ea65..aad2272942 100644 --- a/salt/modules/saltutil.py +++ b/salt/modules/saltutil.py @@ -245,6 +245,25 @@ def update(version=None): return ret +def sync_beacons(saltenv=None, refresh=True): + ''' + Sync the beacons from the _beacons directory on the salt master file + server. This function is environment aware, pass the desired environment + to grab the contents of the _beacons directory, base is the default + environment. + + CLI Example: + + .. code-block:: bash + + salt '*' saltutil.sync_beacons + ''' + ret = _sync('beacons', saltenv) + if refresh: + refresh_beacons() + return ret + + def sync_modules(saltenv=None, refresh=True): ''' Sync the modules from the _modules directory on the salt master file @@ -395,6 +414,7 @@ def sync_all(saltenv=None, refresh=True): ''' log.debug('Syncing all') ret = {} + ret['beacons'] = sync_beacons(saltenv, False) ret['modules'] = sync_modules(saltenv, False) ret['states'] = sync_states(saltenv, False) ret['grains'] = sync_grains(saltenv, False) @@ -407,6 +427,24 @@ def sync_all(saltenv=None, refresh=True): return ret +def refresh_beacons(): + ''' + Signal the minion to refresh the beacons. + + CLI Example: + + .. code-block:: bash + + salt '*' saltutil.refresh_beacons + ''' + try: + ret = __salt__['event.fire']({}, 'beacons_refresh') + except KeyError: + log.error('Event module not available. Module refresh failed.') + ret = False # Effectively a no-op, since we can't really return without an event system + return ret + + def refresh_pillar(): ''' Signal the minion to refresh the pillar data. From 3174227e8ea99d64f88e01bbf324bf70214cc534 Mon Sep 17 00:00:00 2001 From: rallytime Date: Mon, 18 May 2015 13:46:20 -0600 Subject: [PATCH 3/5] Add versionadded directives to new beacon saltutil functions --- salt/modules/saltutil.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/salt/modules/saltutil.py b/salt/modules/saltutil.py index aad2272942..37f54d3af2 100644 --- a/salt/modules/saltutil.py +++ b/salt/modules/saltutil.py @@ -252,6 +252,8 @@ def sync_beacons(saltenv=None, refresh=True): to grab the contents of the _beacons directory, base is the default environment. + .. versionadded:: 2015.5.1 + CLI Example: .. code-block:: bash @@ -271,6 +273,8 @@ def sync_modules(saltenv=None, refresh=True): to grab the contents of the _modules directory, base is the default environment. + .. versionadded:: 2015.5.1 + CLI Example: .. code-block:: bash From dce9b540a6034bbc125dd19ba6760cf9d17f8bb0 Mon Sep 17 00:00:00 2001 From: rallytime Date: Mon, 18 May 2015 14:49:27 -0600 Subject: [PATCH 4/5] Remove extra line --- tests/integration/cloud/providers/digital_ocean.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/integration/cloud/providers/digital_ocean.py b/tests/integration/cloud/providers/digital_ocean.py index c77f43fd1a..ac57f10739 100644 --- a/tests/integration/cloud/providers/digital_ocean.py +++ b/tests/integration/cloud/providers/digital_ocean.py @@ -36,7 +36,6 @@ INSTANCE_NAME = __random_name() PROVIDER_NAME = 'digital_ocean' - class DigitalOceanTest(integration.ShellCase): ''' Integration tests for the DigitalOcean cloud provider in Salt-Cloud From 37dbde6d57163c3bc235034e01b5654a2953f1fd Mon Sep 17 00:00:00 2001 From: "Gareth J. Greenaway" Date: Mon, 18 May 2015 14:06:11 -0700 Subject: [PATCH 5/5] Job already exists in schedule, should return False. --- salt/modules/schedule.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/modules/schedule.py b/salt/modules/schedule.py index abe03bd247..1493c54410 100644 --- a/salt/modules/schedule.py +++ b/salt/modules/schedule.py @@ -292,7 +292,7 @@ def add(name, **kwargs): if name in current_schedule: ret['comment'] = 'Job {0} already exists in schedule.'.format(name) - ret['result'] = True + ret['result'] = False return ret if not name: