def deploy_chef(ask="yes", version="11"): """Install chef-solo on a node""" env.host_string = lib.get_env_host_string() if ask == "no" or littlechef.noninteractive: print("Deploying Chef using omnibus installer version: ...".format(version)) else: message = ('\nAre you sure you want to install Chef version:' '{0} on node {1}?'.format(version, env.host_string)) if not confirm(message): abort('Aborted by user') lib.print_header("Configuring Chef Solo on {0}".format(env.host_string)) if not __testing__: solo.install(version) solo.configure() # Build a basic node file if there isn't one already # with some properties from ohai with settings(hide('stdout'), warn_only=True): output = sudo('ohai -l warn') if output.succeeded: try: ohai = json.loads(output) except ValueError: abort("Could not parse ohai's output" ":\n {0}".format(output)) node = {"run_list": []} for attribute in ["ipaddress", "platform", "platform_family", "platform_version"]: if ohai.get(attribute): node[attribute] = ohai[attribute] chef.save_config(node)
def sync_node(node, on_sync=None): """Builds, synchronizes and configures a node. It also injects the ipaddress to the node's config file if not already existent. """ if node.get('dummy') or 'dummy' in node.get('tags', []): lib.print_header("Skipping dummy: {0}".format(env.host)) return False current_node = lib.get_node(node['name']) # Always configure Chef Solo solo.configure(current_node) ipaddress = _get_ipaddress(node) # Everything was configured alright, so save the node configuration # This is done without credentials, so that we keep the node name used # by the user and not the hostname or IP translated by .ssh/config filepath = save_config(node, ipaddress) try: # Synchronize the kitchen directory _synchronize_node(filepath, node) if on_sync: on_sync() # Execute Chef Solo _configure_node() finally: _node_cleanup() return True
def _node_runner(node_data=None): """This is only used by node so that we can execute in parallel""" env.host_string = lib.get_env_host_string() if node_data: node = node_data else: node = lib.get_node(env.host_string) _configure_fabric_for_platform(node.get("platform")) if node.get("gateway"): gateway = node.get("gateway") else: gateway = env.gateway if node.get("http_proxy"): http_proxy = node.get("http_proxy") else: http_proxy = env.http_proxy if node.get("https_proxy"): https_proxy = node.get("https_proxy") else: https_proxy = env.https_proxy with settings(https_proxy=https_proxy, http_proxy=http_proxy, gateway=gateway): if __testing__: print "TEST: would now configure {0}".format(env.host_string) else: lib.print_header("Configuring {0}".format(env.host_string)) if env.autodeploy_chef and not chef.chef_test(): deploy_chef(ask="no") chef.sync_node(node)
def sync_node(node): """Builds, synchronizes and configures a node. It also injects the ipaddress to the node's config file if not already existent. """ if node.get('dummy') or 'dummy' in node.get('tags', []): lib.print_header("Skipping dummy: {0}".format(env.host)) return False current_node = lib.get_node(node['name']) # Check if node locked if solo.node_locked(current_node): content = json.loads(solo.get_lock_info(current_node)) print colors.yellow("Skipping node {0}.\nLocked by {1}.\nReason: {2}".format(current_node['host_name'], content['author'], content['reason'])) return False # Always configure Chef Solo solo.configure(current_node) ipaddress = _get_ipaddress(node) # Everything was configured alright, so save the node configuration # This is done without credentials, so that we keep the node name used # by the user and not the hostname or IP translated by .ssh/config filepath = save_config(node, ipaddress) try: # Synchronize the kitchen directory _synchronize_node(filepath, node) # Execute Chef Solo _configure_node(node) finally: _node_cleanup() return True
def sync_node(node): """Builds, synchronizes and configures a node. It also injects the ipaddress to the node's config file if not already existent. """ if node.get("dummy") or "dummy" in node.get("tags", []): lib.print_header("Skipping dummy: {0}".format(env.host)) return False # Get merged attributes current_node = _build_node_data_bag() with lib.credentials(): # Always configure Chef Solo solo.configure(current_node) ipaddress = _get_ipaddress(node) # Everything was configured alright, so save the node configuration # This is done without credentials, so that we keep the node name used # by the user and not the hostname or IP translated by .ssh/config filepath = save_config(node, ipaddress) with lib.credentials(): try: # Synchronize the kitchen directory _synchronize_node(filepath, node) # Execute Chef Solo _configure_node() finally: _remove_local_node_data_bag() _node_cleanup() return True
def sync_node(node): """Builds, synchronizes and configures a node. It also injects the ipaddress to the node's config file if not already existent. """ if node.get('dummy') or 'dummy' in node.get('tags', []): lib.print_header("Skipping dummy: {0}".format(env.host)) return False current_node = lib.get_node(node['name']) # Always configure Chef Solo solo.configure(current_node) ipaddress = _get_ipaddress(node) # Everything was configured alright, so save the node configuration # This is done without credentials, so that we keep the node name used # by the user and not the hostname or IP translated by .ssh/config filepath = save_config(node, ipaddress) try: # Synchronize the kitchen directory _synchronize_node(filepath, node) # Execute Chef Solo _configure_node() finally: _node_cleanup() return True
def node(*nodes): """Selects and configures a list of nodes. 'all' configures all nodes""" if not len(nodes) or nodes[0] == '': abort('No node was given') elif nodes[0] == 'all': # Fetch all nodes and add them to env.hosts for node in lib.get_nodes(): env.hosts.append(node['name']) if not len(env.hosts): abort('No nodes found in /nodes/') else: # A list of nodes was given env.hosts = nodes env.all_hosts = list(env.hosts) # Check whether another command was given in addition to "node:" execute = True if 'node:' not in sys.argv[-1]: execute = False # If user didn't type recipe:X, role:Y or deploy_chef, just run configure if execute: for hostname in env.hosts: env.host = hostname env.host_string = hostname lib.print_header("Configuring {0}".format(env.host)) # Read node data and configure node node = lib.get_node(env.host) chef.sync_node(node)
def _node_runner(): """This is only used by node so that we can execute in parallel""" if not env.host_string: abort('no node specified\nUsage: fix node:MYNODES recipe:MYRECIPE') if '@' in env.host_string: env.user = env.host_string.split('@')[0] node = lib.get_node(env.host_string) if __testing__: print "TEST: would now configure {0}".format(env.host_string) else: lib.print_header("Configuring {0}".format(env.host_string)) chef.sync_node(node)
def _node_runner(): """This is only used by node so that we can execute in parallel""" env.host_string = lib.get_env_host_string() node = lib.get_node(env.host_string) _configure_fabric_for_platform(node.get("platform")) if __testing__: print "TEST: would now configure {0}".format(env.host_string) else: lib.print_header("Configuring {0}".format(env.host_string)) chef.sync_node(node)
def configure(): """Configure node using existing config file""" # Check that a node has been selected if not env.host_string: msg = "no node specified\n" msg += "Usage:\n cook node:MYNODE configure" msg += "\n cook node:all configure" abort(msg) lib.print_header("Configuring {0}".format(env.host_string)) # Read node data and configure node node = lib.get_node(env.host_string) chef.sync_node(node)
def configure(): """Configure node using existing config file""" # Check that a node has been selected if not env.host_string: msg = 'no node specified\n' msg += 'Usage:\n cook node:MYNODE configure' msg += '\n cook node:all configure' abort(msg) lib.print_header("Configuring {0}".format(env.host_string)) # Read node data and configure node node = lib.get_node(env.host_string) chef.sync_node(node)
def plugin(name): """Executes the selected plugin Plugins are expected to be found in the kitchen's 'plugins' directory """ env.host_string = lib.get_env_host_string() plug = lib.import_plugin(name) lib.print_header("Executing plugin '{0}' on " "{1}".format(name, env.host_string)) node = lib.get_node(env.host_string) if node == {'run_list': []}: node['name'] = env.host_string plug.execute(node) print("Finished executing plugin")
def _node_runner(): """This is only used by node so that we can execute in parallel""" env.host_string = lib.get_env_host_string() node = lib.get_node(env.host_string) _configure_fabric_for_platform(node.get("platform")) if __testing__: print "TEST: would now configure {0}".format(env.host_string) else: lib.print_header("Configuring {0}".format(env.host_string)) if env.autodeploy_chef and not chef.chef_test(): deploy_chef(ask="no") chef.sync_node(node)
def role(role): """Apply the given role to a node Sets the run_list to the given role If no nodes/hostname.json file exists, it creates one """ # Check that a node has been selected if not env.host_string: abort("no node specified\nUsage: cook node:MYNODE role:MYROLE") lib.print_header("Applying role '{0}' to node {1}".format(role, env.host_string)) # Now create configuration and sync node data = lib.get_node(env.host_string) data["run_list"] = ["role[{0}]".format(role)] chef.sync_node(data)
def plugin(name): """Executes the selected plugin Plugins are expected to be found in the kitchen's 'plugins' directory """ if not env.host_string: abort('No node specified\nUsage: fix node:MYNODES plugin:MYPLUGIN') plug = lib.import_plugin(name) lib.print_header("Executing plugin '{0}' on " "{1}".format(name, env.host_string)) node = lib.get_node(env.host_string) if node == {'run_list': []}: node['name'] = env.host_string plug.execute(node) print("Finished executing plugin")
def role(role): """Apply the given role to a node Sets the run_list to the given role If no nodes/hostname.json file exists, it creates one """ # Check that a node has been selected if not env.host_string: abort('no node specified\nUsage: cook node:MYNODE role:MYROLE') lib.print_header("Applying role '{0}' to node {1}".format( role, env.host_string)) # Now create configuration and sync node data = lib.get_node(env.host_string) data["run_list"] = ["role[{0}]".format(role)] chef.sync_node(data)
def role(role): """Apply the given role to a node Sets the run_list to the given role If no nodes/hostname.json file exists, it creates one """ env.host_string = lib.get_env_host_string() lib.print_header( "Applying role '{0}' to {1}".format(role, env.host_string)) # Now create configuration and sync node data = lib.get_node(env.host_string) data["run_list"] = ["role[{0}]".format(role)] if not __testing__: chef.sync_node(data)
def recipe(recipe): """Apply the given recipe to a node Sets the run_list to the given recipe If no nodes/hostname.json file exists, it creates one """ # Check that a node has been selected if not env.host_string: abort("no node specified\nUsage: fix node:MYNODE recipe:MYRECIPE") lib.print_header("Applying recipe '{0}' on node {1}".format(recipe, env.host_string)) # Now create configuration and sync node data = lib.get_node(env.host_string) data["run_list"] = ["recipe[{0}]".format(recipe)] if not __testing__: chef.sync_node(data)
def recipe(recipe): """Apply the given recipe to a node Sets the run_list to the given recipe If no nodes/hostname.json file exists, it creates one """ env.host_string = lib.get_env_host_string() # Create configuration and sync node data = lib.get_node(env.host_string) data["run_list"] = ["recipe[{0}]".format(recipe)] lib.print_header( "Applying recipe '{0}' on node {1}".format(recipe, env.host_string)) _node_runner(node_data=data)
def recipe(recipe): """Apply the given recipe to a node Sets the run_list to the given recipe If no nodes/hostname.json file exists, it creates one """ env.host_string = lib.get_env_host_string() lib.print_header( "Applying recipe '{0}' on node {1}".format(recipe, env.host_string)) # Create configuration and sync node data = lib.get_node(env.host_string) data["run_list"] = ["recipe[{0}]".format(recipe)] if not __testing__: if env.autodeploy_chef and not chef.chef_test(): deploy_chef(ask="no") chef.sync_node(data)
def role(role): """Apply the given role to a node Sets the run_list to the given role If no nodes/hostname.json file exists, it creates one """ env.host_string = lib.get_env_host_string() lib.print_header("Applying role '{0}' to {1}".format( role, env.host_string)) # Now create configuration and sync node data = lib.get_node(env.host_string) data["run_list"] = ["role[{0}]".format(role)] if not __testing__: if env.autodeploy_chef and not chef.chef_test(): deploy_chef(ask="no") chef.sync_node(data)
def recipe(recipe): """Apply the given recipe to a node Sets the run_list to the given recipe If no nodes/hostname.json file exists, it creates one """ # Check that a node has been selected if not env.host_string: abort('no node specified\nUsage: fix node:MYNODES recipe:MYRECIPE') lib.print_header("Applying recipe '{0}' on node {1}".format( recipe, env.host_string)) # Now create configuration and sync node data = lib.get_node(env.host_string) data["run_list"] = ["recipe[{0}]".format(recipe)] if not __testing__: chef.sync_node(data)
def node(*nodes): """Selects and configures a list of nodes. 'all' configures all nodes""" if not len(nodes) or nodes[0] == '': abort('No node was given') elif nodes[0] == 'all': # Fetch all nodes and add them to env.hosts for node in lib.get_nodes(env.chef_environment): env.hosts.append(node['name']) if not len(env.hosts): abort('No nodes found in /nodes/') message = "Are you sure you want to configure all nodes ({0})".format( len(env.hosts)) if env.chef_environment: message += " in the {0} environment".format(env.chef_environment) message += "?" if not __testing__: if not confirm(message): abort('Aborted by user') else: # A list of nodes was given env.hosts = list(nodes) env.all_hosts = list(env.hosts) # Shouldn't be needed if len(env.hosts) > 1: print "Configuring nodes: {0}...".format(", ".join(env.hosts)) # Check whether another command was given in addition to "node:" execute = True if not(littlechef.__cooking__ and 'node:' not in sys.argv[-1] and 'nodes_with_role:' not in sys.argv[-1]): # If user didn't type recipe:X, role:Y or deploy_chef, # configure the nodes for hostname in env.hosts: env.host = hostname env.host_string = hostname node = lib.get_node(env.host) if node.get('dummy'): lib.print_header("Skipping dummy: {0}".format(env.host)) else: lib.print_header("Configuring {0}".format(env.host)) if __testing__: print "TEST: would now configure {0}".format(env.host) else: chef.sync_node(node)
def roles(*role_list, **kwargs): """Apply the given roles to a node Sets the run_list to the given roles If no nodes/hostname.json file exists, it creates one """ env.host_string = lib.get_env_host_string() lib.print_header( "Applying roles '{0}' to {1}".format(role_list, env.host_string)) override_data = kwargs.get('data', {}) on_sync = kwargs.get('on_sync', None) # Now create configuration and sync node data = lib.get_node(env.host_string) data.update(override_data) data["run_list"] = ["role[{0}]".format(x) for x in role_list] if not __testing__: if env.autodeploy_chef and not chef.chef_test(): deploy_chef(ask="no") chef.sync_node(data, on_sync)
def node(*nodes): """Selects and configures a list of nodes. 'all' configures all nodes""" if not len(nodes) or nodes[0] == '': abort('No node was given') elif nodes[0] == 'all': # Fetch all nodes and add them to env.hosts for node in lib.get_nodes(env.chef_environment): env.hosts.append(node['name']) if not len(env.hosts): abort('No nodes found in /nodes/') message = "Are you sure you want to configure all nodes ({0})".format( len(env.hosts)) if env.chef_environment: message += " in the {0} environment".format(env.chef_environment) message += "?" if not __testing__: if not confirm(message): abort('Aborted by user') else: # A list of nodes was given env.hosts = list(nodes) env.all_hosts = list(env.hosts) # Shouldn't be needed if len(env.hosts) > 1: print "Configuring nodes: {0}...".format(", ".join(env.hosts)) # Check whether another command was given in addition to "node:" execute = True if not (littlechef.__cooking__ and 'node:' not in sys.argv[-1] and 'nodes_with_role:' not in sys.argv[-1]): # If user didn't type recipe:X, role:Y or deploy_chef, # configure the nodes for hostname in env.hosts: env.host = hostname env.host_string = hostname node = lib.get_node(env.host) lib.print_header("Configuring {0}".format(env.host)) if __testing__: print "TEST: would now configure {0}".format(env.host) else: chef.sync_node(node)
def node(*nodes): """Selects and configures a list of nodes. 'all' configures all nodes""" if not len(nodes) or nodes[0] == "": abort("No node was given") elif nodes[0] == "all": # Fetch all nodes and add them to env.hosts for node in lib.get_nodes(): if env.chef_environment is None or node.get("chef_environment") == env.chef_environment: env.hosts.append(node["name"]) if not len(env.hosts): abort("No nodes found in /nodes/") message = "Are you sure you want to configure all nodes ({0})".format(len(env.hosts)) if env.chef_environment: message += " in the {0} environment".format(env.chef_environment) message += "?" if not __testing__: if not confirm(message): abort("Aborted by user") else: # A list of nodes was given env.hosts = list(nodes) env.all_hosts = list(env.hosts) # Shouldn't be needed if len(env.hosts) > 1: print "Configuring nodes: {0}...".format(", ".join(env.hosts)) # Check whether another command was given in addition to "node:" execute = True if littlechef.__cooking__ and "node:" not in sys.argv[-1] and "nodes_with_role:" not in sys.argv[-1]: execute = False # If user didn't type recipe:X, role:Y or deploy_chef, just run configure if execute: for hostname in env.hosts: env.host = hostname env.host_string = hostname lib.print_header("Configuring {0}".format(env.host)) # Read node data and configure node node = lib.get_node(env.host) if not __testing__: chef.sync_node(node)
def deploy_chef(ask="yes", version="13.12.14"): """Install chef-solo on a node""" env.host_string = lib.get_env_host_string() if ask == "no" or littlechef.noninteractive: print("Deploying Chef using omnibus installer version: ...".format( version)) else: message = ('\nAre you sure you want to install Chef version:' '{0} on node {1}?'.format(version, env.host_string)) if not confirm(message): abort('Aborted by user') lib.print_header("Configuring Chef Solo on {0}".format(env.host_string)) if not __testing__: solo.install(version) solo.configure() # Build a basic node file if there isn't one already # with some properties from ohai with settings(hide('stdout'), warn_only=True): output = sudo('ohai -l warn') if output.succeeded: try: ohai = json.loads(output) except ValueError: abort("Could not parse ohai's output" ":\n {0}".format(output)) node = {"run_list": []} for attribute in [ "ipaddress", "platform", "platform_family", "platform_version" ]: if ohai.get(attribute): node[attribute] = ohai[attribute] chef.save_config(node)