def main(): """entry point""" smcscript_dir = get_config_dir() logfile_path = os.path.join(smcscript_dir, "smcscript.log") # os.remove(logfile_path) logging.basicConfig(filename=logfile_path, level=logging.DEBUG) os.chmod(logfile_path, 0o600) logger.info('-' * 60) # if first argument is a file, we assume apply command if len(sys.argv) > 1 and os.path.isfile(sys.argv[1]): sys.argv.insert(1, 'apply') logger.info("Command: %s", ' '.join(sys.argv[1:])) parser = argh.ArghParser() parser.add_commands(cmd_list) try: parser.dispatch() # pylint: disable=broad-except except (CommandError, InvalidSessionError) as err: print_err("Error: {}", unicode(err)) sys.exit(1) except Exception as e: print_err("Unexpected error '{}': {}\n(see {})", type(e).__name__, e, logfile_path) logger.debug("Got unexpected exception: %s", type(e)) logger.exception(e) sys.exit(1)
def _merge_change(): if xpath_expr: matching_nodes = elt.xpath(xpath_expr) if len(matching_nodes) != 1: print_err("error set: {}, number of nodes match: {} "\ "(should be exactly 1)", xpath_expr, len(matching_nodes)) return et_utils.elt_merge(update_elt, matching_nodes[0]) else: et_utils.elt_merge(update_elt, elt)
def _add_change(): if xpath_expr is None: matching_nodes = [elt] else: matching_nodes = elt.xpath(xpath_expr) if len(matching_nodes) != 1: print_err("error adding: {}, number of nodes match: {} "\ "(should be exactly 1)", xpath_expr, len(matching_nodes)) return for elt_to_add in elements: matching_nodes[0].append(elt_to_add)
def _remove_change(): matching_nodes = elt.xpath(xpath_expr) if not matching_nodes: print_err("error deleting {}: element not found", xpath_expr) return if len(matching_nodes) != 1: print_err("error deleting {}, number of elements found: {} "\ "(should be exactly 1)", xpath_expr, len(matching_nodes)) return matching_nodes[0].getparent().remove(matching_nodes[0])
def cmd_login(server, secure=False, port=None, api_key=None, version=None, ca_cert=None, smcrc=None, auto=False): """ login to the smc (rest api) If a file is specified using '-f' or --file, it must have the following format: [smc] smc_address=192.168.100.7 smc_apikey=xxxx api_version=6.4 smc_port=8082 smc_ssl=False verify_ssl=False ssl_cert_file='' """ #todo tls if not server and not smcrc and not auto: raise CommandError("Must have either --file or <server> or --auto") if int(server is not None)+int(smcrc is not None)+int(auto) > 1: raise CommandError("Cannot have both <server> and/or --file and/or --auto") if server and not api_key: raise CommandError("missing --api-key") proto = "https" if secure else "http" url = "{proto}://{host}:{port}".format(host=server, port=port, proto=proto) \ if server else None verify = ca_cert or False sess = SMCSession() try: sess.login(url=url, api_key=api_key, verify=verify, api_version = version, alt_filepath=smcrc) #todo save to another place (env var) if not save_session(sess): print_err("Failed to save session") return "login successful" except SMCConnectionError as conn_error: logger.exception(conn_error) raise CommandError( "connection to '{}:{}' failed\n({})".format(server, port, conn_error))
def do_update_elt(smc_client, target_hname, update_elt, print_only=False): """update a resource element in the smc :param SMCClient smc_client: client to send requests to smc :param etree.Element cmd_elt: element tree, example: update "#single_fw/myfw1" { add "//domain_server_addresses" { domain_server_address { value=8.8.4.4 rank=1.0 } } } :returns: None """ try: smc_elt = smc_client.get(target_hname) except Exception as exc: logger.error(exc) return for operation in update_elt: if operation.tag == "set": xpath_expr = operation.text smc_elt.merge(xpath_expr, operation) elif operation.tag == "del": xpath_expr = operation.text smc_elt.remove(xpath_expr) elif operation.tag == "add": xpath_expr = operation.text smc_elt.add(xpath_expr, *list(operation)) else: print_err("invalid update {}", operation.tag) return smc_client.update(smc_elt, print_only)
def run_script(smc_client, filename, print_only=False, preprocess_only=False, user_variables=None, variable_files=None, ignore_errors=False, delete_mode=False, cleanup_mode=False): """execute a script :param SMCClient smc_client: client to send requests to smc :param str filename: name of the file containing the script :param bool print_only: does not execute the script. only print :param bool preprocess_only: show the script after the template preprocessing :param dict user_variables: dict of name/value used as variables for template preprocessing :returns: None :raises IOError: if filename could not be read :raises TemplateLookupException: failed to include a file :raises NameError: if a variable cannot be resolved :raises SyntaxException: syntax error during preprocessing :raises ElementConfError: failed to parse the filename (after processing) :raises InvalidSessionError: not logged in or session expired :raises SMCOperationFailure: is smc server responds with status_code error """ api_version = smc_client.api_version variables = {'API_VERSION': api_version, 'SCRIPT': smc_client} lookup_dir = os.path.dirname(os.path.abspath(filename)) var_config_file_name = lookup_dir + "/variables.cnf" logger.debug("var_config_file_name=%s", var_config_file_name) # default values from variables.cnf if os.path.isfile(var_config_file_name): logger.debug("opening =%s", var_config_file_name) var_elts = load_config_file(var_config_file_name) logger.debug("var_elts=%s", var_elts) for var_elt in var_elts: name = var_elt.get("name") value = var_elt.get("default") variables[name] = value logger.debug("VAR: %s=%s", name, value) # variables obtained from conf implicit file files = glob('*.cnfvars') for f in files: file_variables = read_variables_from_conf(f) variables.update(file_variables) # variables obtained from conf explicit file (--var-file) for f in variable_files: if not os.path.isfile(f): raise RunScriptError( "variable config file '{}' not found ".format(f)) file_variables = read_variables_from_conf(f) variables.update(file_variables) # variables obtained from env.variables (take precedence from file) for name, value in os.environ.items(): prefix = 'CNF_VAR_' if name.startswith(prefix): var_name = name[len(prefix):] variables[var_name] = value # variables obtained from command-line (take precedence from both # file and env.var) if user_variables: variables.update(user_variables) if preprocess_only: rendered = preprocess_config_file(filename, variables) print(rendered) return conf = load_config_file(filename, variables) if delete_mode or cleanup_mode: print("Cleaning up...") delete_all_resources(smc_client, conf) if delete_mode: return operations = dict(login=do_login, logout=do_logout, resource=do_create_elt, delete=do_delete_elt, update=do_update_elt, command=do_execute, get=do_execute) print("Applying config...") for elt in conf: operation = elt.tag target_hname = _get_target_hname(elt) if operation == 'resource': name = elt[0].attrib.get("name", "") op_text = "{} {}/{}...".format(operation, target_hname, name) else: op_text = "{} {}...".format(operation, target_hname) logging.info("script command: %s", op_text) print_fmt("- {}", op_text) if operation not in operations: raise RunScriptError("invalid operation: " + operation) fun = operations.get(operation) try: fun(smc_client, target_hname, elt, print_only) except (SMCOperationFailure, ResolveError) as exc: if ignore_errors: print_err(" => Ignoring error: {}", unicode(exc)) continue raise SMCOperationFailure(unicode(exc)) return