def test_workflow_transform_skillet(): """ Load and execute the workflow skillet and ensure all child skillets are executed properly :return: None """ skillet_path = '../example_skillets/workflow_transform/' skillet_loader = SkilletLoader(path=skillet_path) skillet: Skillet = skillet_loader.get_skillet_with_name( 'workflow_transform') # verify we can find and load the correct skillet assert skillet.name == 'workflow_transform' out = skillet.execute(context) assert 'pan_validation' in out assert 'outputs' in out assert 'snippets' in out for k, v in out.get('pan_validation', {}).items(): r = str(v.get('results', 'False')) print(f'{k:60}{r}') assert r == 'True' assert 'zones' in skillet.context
def debug_snippets_in_repo(directory: Path, err_list: list) -> list: sl = SkilletLoader() all_skillets = sl.load_all_skillets_from_dir(directory) for e in sl.skillet_errors: err_detail = dict() err_detail['severity'] = 'error' if type(e) is dict: err_detail['path'] = e.get('path', str(directory.absolute())) err_detail['err_list'] = [ e.get('error', 'Could not load Skillet YAML') ] else: err_detail['path'] = str(directory.absolute()) err_detail['err_list'] = [e] err_list.append(err_detail) for skillet in all_skillets: debug_errors = sl.debug_skillet_structure(skillet.skillet_dict) if debug_errors: err_detail = dict() err_detail['path'] = skillet.path err_detail['severity'] = 'error' err_detail['err_list'] = debug_errors err_list.append(err_detail) return err_list
def test_workflow_skillet(): """ Load and execute the workflow skillet and ensure all child skillets are executed properly :return: None """ skillet_path = '../example_skillets/workflow_example/' skillet_loader = SkilletLoader(path=skillet_path) skillet: Skillet = skillet_loader.get_skillet_with_name( 'example_workflow_with_filtering') # verify we can find and load the correct skillet assert skillet.name == 'example_workflow_with_filtering' out = skillet.execute(context) assert 'pan_validation' in out assert 'outputs' in out assert 'snippets' in out # ensure the correct number of tests are included and executed and reported in the output assert len(out['pan_validation']) == 6 # ensure all three snippets were found and executed assert len(skillet.snippet_outputs) == 3
def load_skillet_by_name(self, skillet_name) -> (dict, None): """ Loads application specific skillet :param skillet_name: :return: """ all_skillets = cnc_utils.get_long_term_cached_value( self.app_dir, 'all_snippets') if not all_skillets: all_skillets = list() application_skillets_dir = Path( os.path.join(settings.SRC_PATH, self.app_dir, 'snippets')) skillet_loader = SkilletLoader() app_skillets = skillet_loader.load_all_skillets_from_dir( application_skillets_dir) for s in app_skillets: all_skillets.append(s.skillet_dict) cnc_utils.set_long_term_cached_value(self.app_dir, 'all_snippets', all_skillets, -1) for skillet in all_skillets: if skillet['name'] == skillet_name: return skillet return None
def refresh_skillets_from_repo(repo_name: str) -> list: all_skillets = list() user_dir = os.path.expanduser('~/.pan_cnc') app_name = get_default_app_name() snippets_dir = os.path.join(user_dir, app_name, 'repositories') repo_dir = os.path.join(snippets_dir, repo_name) if not os.path.exists(repo_dir): print(f'Repository {repo_dir} does not exist!') return all_skillets try: repo_object = RepositoryDetails.objects.get(name=repo_name) sl = SkilletLoader() found_skillets = sl.load_all_skillets_from_dir(repo_dir) for skillet_object in found_skillets: skillet_name = skillet_object.name (skillet_record, created) = Skillet.objects.get_or_create( name=skillet_name, defaults={ 'skillet_json': json.dumps(skillet_object.skillet_dict), 'repository_id': repo_object.id, } ) if not created: if skillet_record.repository_id == repo_object.id: # check if skillet contents have been updated found_skillet_json = json.dumps(skillet_object.skillet_dict) if skillet_record.skillet_json != found_skillet_json: skillet_record.skillet_json = found_skillet_json skillet_record.save() else: print(f'Found existing skillet from another repository: {skillet_name}!!') raise DuplicateSkilletException( f'Refusing to import duplicate Skillet: {skillet_name}' ) for db_skillet in repo_object.skillet_set.all(): found = False for found_skillet in found_skillets: if db_skillet.name == found_skillet.name: found = True continue if not found: db_skillet.delete() update_skillet_cache() return load_skillets_from_repo(repo_name) except ObjectDoesNotExist: return all_skillets
def cli(target_ip, target_port, target_username, target_password, include_svc_setup, infra_subnet, infra_bgp_as, portal_hostname, deployment_region, deployment_locations_americas, deployment_locations_europe, deployment_locations_apac, ip_pool_cidr, user1_password, user2_password, conf_filename): """ Import a full configuration. Defaults values in parenthesis. """ # creating the jinja context from the skillet vars print('Reading in skillet variables') context = dict() context['include_svc_setup'] = include_svc_setup context['infra_subnet'] = infra_subnet context['infra_bgp_as'] = infra_bgp_as context['portal_hostname'] = portal_hostname context['deployment_region'] = deployment_region context['deployment_locations_americas'] = deployment_locations_americas.split(',') context['deployment_locations_europe'] = deployment_locations_europe.split(',') context['deployment_locations_apac'] = deployment_locations_apac.split(',') context['ip_pool_cidr'] = ip_pool_cidr context['user1_password'] = user1_password context['user2_password'] = user2_password context['conf_filename'] = conf_filename try: # render the template config file and create file_contents to use with import_file print('Creating the configuration file') sl = SkilletLoader() skillet = sl.load_skillet_from_path('../mobile_full_config') output = skillet.execute(context) file_contents = output.get('template', '') # create device object and use panoply import_file to send a config file to the device print('Import the config file to Panorama') device = Panos(api_username=target_username, api_password=target_password, hostname=target_ip, api_port=target_port ) if not device.import_file(conf_filename, file_contents, 'configuration'): exit(1) exit(0) except LoginException as lxe: print(lxe) exit(1) except SkilletLoaderException as pe: print(pe) exit(1) # failsafe exit(1) print('File import complete')
def load_and_dump_skillet(skillet_path: str) -> str: skillet_loader = SkilletLoader() skillet = skillet_loader.load_skillet_from_path(skillet_path) print('=' * 80) print(f'Checking {skillet.label}\n'.center(80)) output: str = skillet.dump_yaml() return output
def load_and_execute_skillet(skillet_path: str) -> dict: skillet_loader = SkilletLoader() skillet = skillet_loader.load_skillet_from_path(skillet_path) print('=' * 80) print(f'Executing {skillet.label}\n'.center(80)) output: dict = skillet.execute(context) return output
def test_get_skillet_by_name(): """ Test to verify skilletLoader can successfully load all skillets found in the 'skillet_incluedes' directory and return the one with the 'include_other_skillets' name :return: None """ skillet_path = '../example_skillets/skillet_includes/' skillet_loader = SkilletLoader(path=skillet_path) skillet = skillet_loader.get_skillet_with_name('include_other_skillets') assert skillet is not None
def test_load_skillet(): """ Test to verify skilletLoader can successfully load all skillets found in the 'workflow_example' directory and return the one with the 'example_workflow_with_filtering' name :return: None """ skillet_path = '../example_skillets/workflow_example/' skillet_loader = SkilletLoader(path=skillet_path) skillet = skillet_loader.get_skillet_with_name( 'example_workflow_with_filtering') assert skillet is not None
def test_skillet_includes(): """ Tests to verify the Skillet object is successfully compiled from all included skillets. The 'include_other_skillets' skillet includes snippets and variables from two other skillets in the same directory :return: None """ skillet_path = '../example_skillets/skillet_includes/' skillet_loader = SkilletLoader(path=skillet_path) skillet: Skillet = skillet_loader.get_skillet_with_name( 'include_other_skillets') # verify we can find and load the correct skillet assert skillet.name == 'include_other_skillets' # verify the correct number of snippets. assert len(skillet.snippets) == 9 included_snippet: Snippet = skillet.get_snippet_by_name( 'network_profiles.check_network_profiles') # verify we can get an included snippet from the skillet object assert included_snippet is not None # verify the 'label' metadata attribute has been overridden correctly assert included_snippet.metadata.get( 'label', '') == 'Check Network Profiles Override' included_variable: dict = skillet.get_variable_by_name('another_variable') # verify the included variable is present in the compiled skillet assert included_variable is not None # verify the default value is correctly overridden from the included variable assert included_variable.get('default', '') == 'test123456' second_included_variable: dict = skillet.get_variable_by_name( 'some_update_variable') assert second_included_variable is not None another_included_variable: dict = skillet.get_variable_by_name( 'zone_to_test') assert another_included_variable["default"] == "untrust" # Ensure using includes / overrides leaves our original skillet definition intact # added for issue #163 child_skillet: Skillet = skillet_loader.get_skillet_with_name( 'network_profiles') child_snippet: Snippet = child_skillet.get_snippet_by_name( 'check_network_profiles') assert child_snippet.metadata.get('label', '') == 'Ensure Named profile exists'
def cli(skillet_path, target_ip, target_port, target_username, target_password, env_file): """ Load the Skillet from the command line. Defaults values in parenthesis. """ try: sl = SkilletLoader() skillet = sl.load_skillet_from_path(skillet_path) if env_file is not None: try: with open(env_file, 'r') as ef: context = yaml.safe_load(ef.read()) except yaml.YAMLError: context = os.environ.copy() else: context = skillet.update_context(os.environ.copy()) if skillet.type == 'panos': device = Panos(api_username=target_username, api_password=target_password, hostname=target_ip, api_port=target_port ) skillet.panoply = device output = skillet.execute(context) # FIXME - context should always include a key indicating success / failure of the given skillet # we may need situations where a failure doesn't necessarily raise an exception and we should handle # this here. Possibly for things likes like - skillet already applied, no action taken, or some # check failed... if output.get('result', 'failure') == 'success': msg = device.commit() # msg = 'no commit for testing, commit commented out for now' print(f'Successfully executed Skillet {skillet.name} for host: {target_ip}') print(f'commit message was: {msg}') print(f'output was: {context}') exit(0) else: exit(1) except LoginException as lxe: print(lxe) exit(1) except SkilletLoaderException as lde: print(lde) exit(1) # failsafe exit(1)
def refresh_skillets_from_repo(repo_name: str) -> list: all_skillets = list() user_dir = os.path.expanduser('~/.pan_cnc') app_name = get_default_app_name() snippets_dir = os.path.join(user_dir, app_name, 'repositories') repo_dir = os.path.join(snippets_dir, repo_name) try: repo_object = RepositoryDetails.objects.get(name=repo_name) sl = SkilletLoader() found_skillets = sl.load_all_skillets_from_dir(repo_dir) for skillet_object in found_skillets: skillet_name = skillet_object.name (skillet_record, created) = Skillet.objects.get_or_create( name=skillet_name, defaults={ 'skillet_json': json.dumps(skillet_object.skillet_dict), 'repository_id': repo_object.id, }) if not created: # check if skillet contents have been updated found_skillet_json = json.dumps(skillet_object.skillet_dict) if skillet_record.skillet_json != found_skillet_json: skillet_record.skillet_json = found_skillet_json skillet_record.save() for db_skillet in repo_object.skillet_set.all(): found = False for found_skillet in found_skillets: if db_skillet.name == found_skillet.name: found = True continue if not found: db_skillet.delete() update_skillet_cache() return load_skillets_from_repo(repo_name) except ObjectDoesNotExist: return all_skillets
def test_load_skillet_from_path(): skillet_path = '../example_skillets/skillet_includes/include_other_skillets.skillet.yaml' skillet_loader = SkilletLoader() skillet = skillet_loader.load_skillet_from_path(skillet_path) # verify we can find and load the correct skillet assert skillet.name == 'include_other_skillets' # verify the correct number of snippets. assert len(skillet.snippets) == 9 included_snippet: Snippet = skillet.get_snippet_by_name( 'network_profiles.check_network_profiles') # verify we can get an included snippet from the skillet object assert included_snippet is not None
def main(): # define available arguments/parameters a user can pass to the module module_args = dict(skillet=dict(type='str', required=True), skillet_path=dict(type='str', required=True), vars=dict(type='dict'), provider=dict(type='dict', required=True)) module = AnsibleModule( argument_spec=module_args, supports_check_mode=False, ) # create our context dict. Every skillet requires a context that contains connection information # as well as any vars required for that particular skillet skillet_context = dict() skillet_context.update(module.params['vars']) skillet_context.update(module.params['provider']) skillet_loader = SkilletLoader(module.params['skillet_path']) skillet = skillet_loader.get_skillet_with_name(module.params['skillet']) if skillet is None: module.fail_json(msg='Could not find Skillet with name {0}'.format( module.params['name'])) # refuse to run any non panos / panorama skillet types if not skillet.type == 'pan_validation': module.fail_json(msg='Invalid Skillet Type') try: output = skillet.execute(skillet_context) output_str = json.dumps(output) for snippet in output['pan_validation']: if not output['pan_validation'][snippet]['results']: module.fail_json(msg=output_str) module.exit_json(changed=False, stdout=output_str) except PanoplyException as p: module.fail_json(msg='{0}'.format(p))
def load_and_execute_skillet(skillet_path: str) -> None: skillet_loader = SkilletLoader(path=skillet_path) skillet = skillet_loader.skillets[0] print('=' * 80) print(f'Executing {skillet.label}\n'.center(80)) output = skillet.execute(context) if 'pan_validation' in output: for k, v in output.get('pan_validation', {}).items(): r = str(v.get('results', 'False')) print(f'{k:60}{r}') assert r == 'True'
def cli(skillet_path, target_ip, target_port, target_username, target_password): """ Load the Skillet from the command line. Defaults values in parenthesis. """ try: sl = SkilletLoader() skillet = sl.load_skillet_from_path(skillet_path) context = skillet.update_context(os.environ.copy()) if skillet.type == 'panos': device = Panoply(api_username=target_username, api_password=target_password, hostname=target_ip, api_port=target_port) # set the device object on the skillet object skillet.panoply = device skillet.execute(context) print('Performing Commit') device.commit() print( f'Successfully pushed Skillet {skillet.name} to host: {target_ip}' ) exit(0) except LoginException as lxe: print(lxe) exit(1) except SkilletLoaderException as lde: print(lde) exit(1) # failsafe exit(1)
def cli(skillet_path, target_ip, target_port, target_username, target_password): """ Render a full configuration template, import it into the device and load it """ try: # ensure skillet_path contains the skillet you want as this will just load them all sl = SkilletLoader(skillet_path) # grab first skillet from list skillet = sl.skillets[0] # this allows any variables needed for the template skillet too be passed in # via env vars. Especially useful for Jenkins and docker type deployments context = skillet.update_context(os.environ.copy()) if skillet.type == 'template': device = Panoply(api_username=target_username, api_password=target_password, hostname=target_ip, api_port=target_port) output = skillet.execute(context) template = output.get('template', None) if template is None: print('Could not render template') exit(1) snippet = skillet.snippet_stack[0] device.import_file(snippet.get('name', 'loaded_config'), template, 'configuration') device.load_config(snippet.get('name', 'loaded_config')) print('Performing commit...') device.commit() print( f'Successfully imported and loaded Skillet {skillet.name} to host: {target_ip}' ) exit(0) except LoginException as lxe: print(lxe) exit(1) except SkilletLoaderException as lde: print(lde) exit(1) # failsafe exit(1)
print('Appetizer Configuration file already found!') exit(0) print('Building Appetizer Configuration ...') repo = os.environ.get( 'REPO', 'https://github.com/PaloAltoNetworks/SkilletBuilder.git') repo_branch = os.environ.get('BRANCH', 'master') repo_name = os.environ.get('NAME', 'appetizer') local_dir = os.path.expanduser('~/.pan_cnc/appetizer/repositories') if not os.path.exists(local_dir): os.makedirs(local_dir) sl = SkilletLoader() repo_full_dir = os.path.join(local_dir, repo_name) if os.path.exists(repo_full_dir): print('Using local dir') all_skillets = sl.load_all_skillets_from_dir(repo_full_dir) else: print(f'Pulling anew into {local_dir}') # do not check for self signed certs here os.environ['GIT_SSL_NO_VERIFY'] = "1" all_skillets = sl.load_from_git(repo, repo_name, repo_branch, local_dir=local_dir) src_dir = os.path.join(repo_full_dir, 'src')
#!/usr/bin/env python3 from skilletlib import SkilletLoader sl = SkilletLoader('.') skillet = sl.get_skillet_with_name('panos_cli_example') context = dict() context['cli_command'] = 'show system info' context['username'] = '******' context['password'] = '******' context['ip_address'] = 'NOPE' output = skillet.execute(context) print(output.get('output_template', 'n/a'))
def test_skillet_includes(): """ Tests to verify the Skillet object is successfully compiled from all included skillets. The 'include_other_skillets' skillet includes snippets and variables from two other skillets in the same directory :return: None """ skillet_path = '../example_skillets/skillet_includes/' skillet_loader = SkilletLoader(path=skillet_path) skillet: Skillet = skillet_loader.get_skillet_with_name( 'include_other_skillets') # verify we can find and load the correct skillet assert skillet.name == 'include_other_skillets' # verify the correct number of snippets. assert len(skillet.snippets) == 14 # Check that parent snippets and variables are brought in correctly not_included_snippet: Snippet = skillet.get_snippet_by_name('parse_config') # verify that non-included snippets are appended to the skillet, from include_other_skillets assert not_included_snippet is not None parent_preserve_variable: dict = skillet.get_variable_by_name( 'shared_base_variable') # verify that the override variables brought up to the parent are preserved assert "toggle_hint" not in parent_preserve_variable # Check that a snippet of this format is brought in correctly # - name: something # include: child_skillet simple_include_snippet: Snippet = skillet.get_snippet_by_name( 'update_schedule.get_update_schedule') # verify that snippet with just include: keyword is brought in properly, from update_schedule assert simple_include_snippet is not None simple_include_variable: dict = skillet.get_variable_by_name( 'some_update_variable') # verify that variable with just include: keyword is brought in properly, from update_schedule assert simple_include_variable is not None # Check that a snippet of this format is brought in correctly # - name: something # include: child_skillet # include_snippets: # - name: snippet_1 # attribute: included_snip_only_snippet: Snippet = skillet.get_snippet_by_name( 'network_profiles.check_network_profiles') # verify we can get an included snippet from the skillet object assert included_snip_only_snippet is not None # verify the 'label' metadata attribute has been overridden correctly assert included_snip_only_snippet.metadata.get( 'label', '') == 'Check Network Profiles Override' included_snip_only_variable: dict = skillet.get_variable_by_name( 'another_variable') # verify the child variable is present in compiled skillet assert included_snip_only_variable is not None # Check that a snippet of this format is brought in correctly # - name: something # include: child_skillet # include_variables: # - name: variable_1 # attribute: included_var_only_snippet: Snippet = skillet.get_snippet_by_name( 'check_zones.ensure_desired_zone') # verify we can get an included snippet from the skillet object assert included_var_only_snippet is not None included_var_only_variable: dict = skillet.get_variable_by_name( 'zone_to_test') # verify the child's default gets overridden because of the parent's attribute definition assert included_var_only_variable["default"] == "untrust" # Check that a snippet of this format is brought in correctly # - name: something # include: child_skillet # include_variables: # - name: all # attribute: merge_snip_snippet: Snippet = skillet.get_snippet_by_name( "qos_class.qos_parse") # verify that the snippets get added to compiled snippet assert merge_snip_snippet is not None merged_override_from_all_variable: dict = skillet.get_variable_by_name( 'qos_class') # verify that shared children variables merge attributes assert merged_override_from_all_variable["toggle_hint"] is not None assert "internet" in merged_override_from_all_variable["toggle_hint"][ "value"] assert "untrust" in merged_override_from_all_variable["toggle_hint"][ "value"] child_override_1_variable: dict = skillet.get_variable_by_name( 'child_1_unique_variable') # verify that child override works assert child_override_1_variable["toggle_hint"] is not None child_override_2_variable: dict = skillet.get_variable_by_name( 'child_2_unique_variable') # verify that child override works assert child_override_2_variable["toggle_hint"] is not None # Added for issue #163 child_skillet: Skillet = skillet_loader.get_skillet_with_name( 'network_profiles') child_snippet: Snippet = child_skillet.get_snippet_by_name( 'check_network_profiles') # ensure using includes / overrides leaves our original skillet definition intact assert child_snippet.metadata.get('label', '') == 'Ensure Named profile exists'
print('Error Executing Skillet') print(se) sys.exit(1) except LoginException as le: print('Error Logging into device') print(le) sys.exit(1) # check we actually have some diffs if len(snippets) == 0: print('No Diffs found between these two configs') sys.exit(2) # SkilletLoader is used to... Load Skillets skillet_loader = SkilletLoader() # create_skillet will return a Skillet Object from the metadata dictionary passed in. # in this case, we create a minimal metadata dict and pass it in to create a simple 'template' skillet # a template skillet is a nice wrapper around the jinja engine template_skillet = skillet_loader.create_skillet( {'type': 'template', 'snippets': [ {'name': 'template', 'file': './ansible_pb_template.j2'} ] } ) # to execute this skillet, create the context object which includes any variables found in the template file context = dict() context['snippets'] = snippets
# copyright notice and this permission notice appear in all copies. # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # Authors: Nathan Embery from skilletlib import SkilletLoader # use skilletLoader from skilletlib to load and execute the skillet sl = SkilletLoader() # our skillet is located in the same directory skillet = sl.load_skillet_from_path('.') # each skillet can specify what items are customizable. # Create a context dictionary to hold our customized variables for this execution. context = dict() context['username'] = '******' context['password'] = '******' context['ip_address'] = '10.10.10.10' # This Ansible playbook may take a very long time. Use the 'execute_async' method to poll for the output as it happens # As with the execute method, we pass in our context object # The primary different is 'execute_async' returns a generator that we can iterate over to get the output as it happens # from the docker container
except LoginException as le: print('Error Logging into device') print(le) exit(1) else: config = os.environ.get('config', '') skillet_content_raw = os.environ.get('SKILLET_CONTENT', '') debug = os.environ.get('DEBUG', False) # because we are passing this value around, we may need to unescape it here skillet_content = html.unescape(skillet_content_raw) sl = SkilletLoader() # get the full contents of the environment to initialize the skillet context try: context = dict() context['config'] = config # create the skillet definition from the 'skillet_content' dict we got from the environ skillet_dict_raw = oyaml.safe_load(skillet_content) # use skilletLoader to normalize the skillet definition and fix common config file errors skillet_dict = sl.normalize_skillet_dict(skillet_dict_raw) skillet_dict['snippet_path'] = '.' # create the skillet object from the skillet dict if 'pan_validation' in skillet_dict.get('type'):
def execute_docker_skillet(skillet_def: dict, args: dict) -> str: """ Execute a skillet of type 'docker'. This requires the calling application have access to the docker socket :param skillet_def: the skillet as loaded from the YAML file (dict) :param args: context arguments required for the given skillets. These will overwrite the 'variables' in the skillet :return: JSON encoded string with dict containing the following keys: {'returncode', 'out', 'err'} """ state = dict() full_output = '' err = '' rc = 0 docker_helper = DockerHelper() if skillet_def['type'] != 'docker' and skillet_def['type'] != 'terraform': rc = 255 err = f'Not a valid skillet type: {skillet_def["type"]}!' elif not docker_helper.check_docker_server(): rc = 240 err = 'Could not connect to Docker daemon, verify permissions on the docker socket! \n\n' \ 'See the documentation for details: https://panhandler.readthedocs.io/en/master/debugging.html' else: try: persistent_volumes = docker_helper.get_cnc_volumes() if 'app_data' not in skillet_def: skillet_def['app_data'] = dict() # always overwrite any volumes that may have snuck in here if persistent_volumes: skillet_def['app_data']['volumes'] = persistent_volumes else: # only this app should be setting app_data/volumes here, remove anything else if 'volumes' in skillet_def['app_data']: skillet_def['app_data'].pop('volumes') sl = SkilletLoader() skillet = sl.create_skillet(skillet_def) # FIX for #181 sanitized_args = __santize_args(args) output_generator = skillet.execute_async(sanitized_args) for out in output_generator: full_output += out current_task.update_state(state='PROGRESS', meta=full_output) r = skillet.get_results() # FIXME - docker skillets can run multiple snippets / cmds inside the container # should check for the output of each and determine if a single failure is considered a failure # for the entire skillet or only a failure for one step ? if isinstance(r, dict) and 'snippets' in r: for k, v in r['snippets'].items(): result = v.get('results', 'failure') if result == 'success': full_output = v.get('raw', '') elif result == 'error' or 'fail' in result: err = v.get('raw', 'error') rc = 2 else: full_output = v.get('raw', '') err = f'Unknown return value type {result}' rc = 3 else: full_output = r err = 'unknown output from skillet' except DockerHelperException as dee: logger.error(dee) rc = 1 err = str(dee) except SkilletLoaderException as sle: logger.error(sle) rc = 1 err = str(sle) state['returncode'] = rc state['out'] = full_output state['err'] = err return json.dumps(state)
print("Error Executing Skillet") print(se) sys.exit(1) except LoginException as le: print("Error Logging into device") print(le) sys.exit(1) # check we actually have some diffs if len(snippets) == 0: print("No Diffs found between these two configs") sys.exit(2) # SkilletLoader is used to... Load Skillets skillet_loader = SkilletLoader() # create_skillet will return a Skillet Object from the metadata dictionary passed in. # in this case, we create a minimal metadata dict and pass it in to create a simple 'template' skillet # a template skillet is a nice wrapper around the jinja engine template_skillet = skillet_loader.create_skillet( {"type": "template", "snippets": [{"name": "template", "file": "./ansible_pb_template.j2"}]} ) # to execute this skillet, create the context object which includes any variables found in the template file context = dict() context["snippets"] = snippets context["playbook_name"] = "Auto Generated PAN-OS Playbook" # execute the template skillet and get the returned output output = template_skillet.execute(context)