def test_get_node(self): """Should get data for a given node, empty when it doesn't exist""" # Unexisting node expected = {"run_list": []} self.assertEquals(lib.get_node('Idon"texist'), expected) # Existing node expected = {"chef_environment": "production", "name": "testnode1", "run_list": ["recipe[subversion]"]} self.assertEquals(lib.get_node("testnode1"), expected)
def test_get_node(self): """Should get data for a given node, empty when it doesn't exist""" # Unexisting node expected = {'run_list': []} self.assertEqual(lib.get_node('Idon"texist'), expected) # Existing node expected = { 'chef_environment': 'production', 'name': 'testnode1', 'run_list': ['recipe[subversion]'], } self.assertEqual(lib.get_node('testnode1'), expected)
def test_get_node(self): """Should get data for a given node, empty when it doesn't exist""" # Unexisting node expected = {'run_list': []} self.assertEquals(lib.get_node('Idon"texist'), expected) # Existing node expected = { 'chef_environment': 'production', 'name': 'testnode1', 'run_list': ['recipe[subversion]'], } self.assertEquals(lib.get_node('testnode1'), expected)
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 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 _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 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') path = os.path.join("plugins", name + ".py") if not os.path.exists(path): abort("Sorry, could not find '{0}.py' in the plugin directory".format( name)) import imp try: with open(path, 'rb') as f: plug = imp.load_module("p_" + name, f, name + '.py', ('.py', 'rb', imp.PY_SOURCE)) except Exception as e: error = "Found plugin '{0}',".format(name) error += " but it seems to have a syntax error: {0}".format(str(e)) abort(error) print("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 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 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') path = os.path.join("plugins", name + ".py") if not os.path.exists(path): abort("Sorry, could not find '{0}.py' in the plugin directory".format( name)) import imp try: with open(path, 'rb') as f: plug = imp.load_module( "p_" + name, f, name + '.py', ('.py', 'rb', imp.PY_SOURCE) ) except Exception as e: error = "Found plugin '{0}',".format(name) error += " but it seems to have a syntax error: {0}".format(str(e)) abort(error) print("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 test_get_node_default_env(self): """Should set env to _default when node sets no chef_environment""" expected = { 'chef_environment': '_default', 'name': 'nestedroles1', 'run_list': ['role[top_level_role]'], } self.assertEqual(lib.get_node('nestedroles1'), expected)
def test_get_node_found(self): """Should get node data when node is found""" expected = { 'chef_environment': 'production', 'name': 'testnode1', 'run_list': ['recipe[subversion]'], } self.assertEqual(lib.get_node('testnode1'), expected)
def unlock_node(node): """Calls unlocker from solo""" current_node = lib.get_node(node['name']) if solo.node_locked(current_node): solo.unlock(current_node) record_chef_run(node, "successful", "") else: print "Failed to unlock node. Node {0} is not locked.".format(current_node['host_name'])
def test_get_node_not_found(self): """Should get empty template when node is not found""" name = 'Idon"texist' expected = { 'chef_environment': '_default', 'name': name, 'run_list': [] } self.assertEqual(lib.get_node(name), expected)
def test_get_node_default_env(self): """Should set env to _default when node sets no chef_environment""" expected = { 'chef_environment': '_default', 'name': 'nestedroles1', 'run_list': ['role[top_level_role]'], 'tags': ['top'], } self.assertEqual(lib.get_node('nestedroles1'), expected)
def lock_node(node, reason): """"Calls locker with settings,current_node and action variables""" current_node = lib.get_node(node['name']) if solo.node_locked(current_node): content = json.loads(solo.get_lock_info(current_node)) print colors.yellow("Node {0} already locked by {1}.\nReason: {2}".format(current_node['host_name'], content['author'], content['reason'])) raise SystemExit else: solo.lock(current_node, reason) print colors.green("Node {0} locked".format(current_node['host_name'])) record_chef_run(node, "successful", reason)
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 _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 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 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) print("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 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 """ 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 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 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 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 """ 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 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 test_get_node(self): """Should get data for a given node, empty when it doesn't exist""" expected = {'run_list': []} self.assertEquals(lib.get_node('Idon"texist'), expected) expected = {'run_list': ['recipe[subversion]']} self.assertEquals(lib.get_node('testnode1'), expected)
def test_get_node_not_found(self): """Should get empty template when node is not found""" name = 'Idon"texist' expected = {'chef_environment': '_default', 'name': name, 'run_list': []} self.assertEqual(lib.get_node(name), expected)