forked from cu-csc/automaton
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request cu-csc#4 from alal3177/staged-deployment
skeleton of the staged deployment
- Loading branch information
Showing
11 changed files
with
360 additions
and
1 deletion.
There are no files selected for viewing
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
""" | ||
Set of functions that are common among deployment classes. | ||
""" | ||
|
||
import os | ||
|
||
from lib import util | ||
|
||
def get_run_levels(dir_path): | ||
"""Return sorted list of directory content | ||
Args: | ||
dir_path ( string ) : directory path | ||
Return: | ||
list or bool | ||
""" | ||
try: | ||
contents = [] | ||
folder_contents = sorted(os.listdir(dir_path)) | ||
for item in folder_contents: | ||
item_first_chr = item.split("-")[0] | ||
try: | ||
if os.path.isdir(os.path.join(dir_path,item)) and item_first_chr.isdigit(): | ||
contents.append(item) | ||
except: | ||
continue | ||
|
||
return contents | ||
except OSError: | ||
return False | ||
|
||
def get_executable_files(run_level_dir): | ||
"""get executable files from a directory | ||
Given a directory, walk into it and return absolute path of files that are executable | ||
Args: | ||
run_level_dir ( string ) : directory path | ||
Return : | ||
scripts_list ( list ) : contains all executable files | ||
""" | ||
scripts_list = [] | ||
for root, dirs, files in os.walk(run_level_dir): | ||
for afile in files: | ||
file_abs_path = os.path.join(root,afile) | ||
if util.is_executable_file(file_abs_path): | ||
scripts_list.append(os.path.join(root,afile)) | ||
return scripts_list | ||
|
||
|
||
def get_stages(mode, levels_dir, remote_dir=""): | ||
""" Get the stages of execution in a dict format | ||
Given a root directory of the stages, loop over those levels and extract all executable scripts | ||
based on given mode, i.e : client or server. | ||
Args: | ||
mode (string) : client or server | ||
levels_dir (string) : deployment stage root dir | ||
return: | ||
stages_dict (dict) : every key represent an execution level, the value of that key is list of all | ||
executable scripts in that level. | ||
""" | ||
stages_dict = {} | ||
levels = get_run_levels(levels_dir) | ||
if levels: | ||
for level in levels: | ||
abs_path = os.path.join(levels_dir, level) | ||
if level.startswith("0-"): | ||
tmp_exec_files = get_executable_files(abs_path) | ||
if tmp_exec_files: | ||
stages_dict[level] = get_executable_files(abs_path) | ||
else: | ||
abs_path_w_mode = os.path.join(abs_path, mode) | ||
stages_dict[level] = get_executable_files(abs_path_w_mode) | ||
|
||
for key, value in stages_dict.iteritems(): | ||
stages_dict[key] = [ x.replace(levels_dir,remote_dir,1) for x in value ] | ||
|
||
return stages_dict |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
""" | ||
implements the staged deployment engine which contains the logic and | ||
order of execution | ||
""" | ||
|
||
class StagedDeploymentEngine(object): | ||
|
||
def __init__(self): | ||
raise NotImplementedError |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
""" | ||
Module that handle the staged deployment execution | ||
""" | ||
|
||
from lib import util | ||
|
||
|
||
class Executor(object): | ||
|
||
def __init__(self, hostname, private_key, staged_dict): | ||
self.hostname = hostname | ||
self.private_key = private_key | ||
self.staged_dict = staged_dict | ||
|
||
def execute_one_level(self, run_level): | ||
|
||
result_dict = {} | ||
cmds_in_run_level = self.staged_dict[run_level] | ||
|
||
for command in cmds_in_run_level: | ||
remote_command = util.RemoteCommand(self.hostname, self.private_key, command) | ||
return_code = remote_command.execute() | ||
result_dict[command] = (return_code, remote_command.stdout, remote_command.stderr) | ||
|
||
if return_code != 0: | ||
break | ||
return result_dict |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,6 @@ | ||
[DEFAULT] | ||
key_name = automaton | ||
key_path = /Users/dmdu/.ssh/id_rsa_futuregrid.pub | ||
key_path = /Users/dmdu/.ssh/id_rsa_futuregrid.pub | ||
ssh_priv_key = /Users/ali/.ssh/ali_alzabarah_fg.priv | ||
git_repo_home = /home/staged-deployment-scripts | ||
git_repo_location = https://github.com/alal3177/staged-deployment-scripts.git |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
""" | ||
This entire file is just an example to demonstrate functionality of staged deployment. | ||
We will implement the execution workflow here when we have more time. | ||
""" | ||
|
||
import shutil | ||
|
||
from lib import util | ||
from deployment import common | ||
from deployment.executor import Executor | ||
|
||
# config file path | ||
config_file = "../etc/global.conf" | ||
|
||
# clone the repo locally | ||
my_local_folder = util.clone_git_repo(util.read_config(config_file).get("DEFAULT","git_repo_location")) | ||
|
||
# we fill a dict with our stages | ||
stages = common.get_stages("client", my_local_folder, util.read_config(config_file).get("DEFAULT","git_repo_home")) | ||
|
||
|
||
# remove the directory since it is not needed anymore | ||
shutil.rmtree(my_local_folder,ignore_errors=True) | ||
|
||
# clone the repo to the vm | ||
remote_clone_result = util.RemoteCommand("vm-148-120.uc.futuregrid.org",\ | ||
util.read_config(config_file).get("DEFAULT", "ssh_priv_key"), | ||
"git clone %s %s" % (util.read_config(config_file).get("DEFAULT","git_repo_location") , | ||
util.read_config(config_file).get("DEFAULT","git_repo_home"))).execute() | ||
|
||
# initiate executor class with the stages | ||
exec_obj = Executor("vm-148-120.uc.futuregrid.org", | ||
util.read_config(config_file).get("DEFAULT", "ssh_priv_key"), | ||
stages) | ||
|
||
# loop over all available stages that has a script with execution bit set and execute it | ||
# if any of the commands at stage 0 failed for example, then we abort the execution and do not go | ||
# to next stage | ||
|
||
abort = False | ||
for each_stage in stages: | ||
if not abort: | ||
all_commands_result = exec_obj.execute_one_level(each_stage) | ||
print "done with %s and all commands results are : %s" % (each_stage, str(all_commands_result)) | ||
for command_result in all_commands_result: | ||
result, stdout, stderr = all_commands_result[command_result] | ||
if result != 0: | ||
abort = True | ||
break | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Fabric==1.4.3 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
""" | ||
Module that tests various deployment functionality | ||
To run me from command line: | ||
cd automaton/tests | ||
export PYTHONPATH=$PYTHONPATH:../ | ||
python -m unittest -v deployment_tests | ||
unset PYTHONPATH | ||
I should have used nose but | ||
""" | ||
|
||
import unittest | ||
|
||
|
||
from lib import util | ||
from deployment import common | ||
|
||
class test_deployment_functions(unittest.TestCase): | ||
|
||
def setUp(self): | ||
self.testing_machine = "vm-148-120.uc.futuregrid.org" | ||
self.bad_machine_name = "Idonotexistwallah.wrong" | ||
self.key_filename = "/Users/ali/.ssh/ali_alzabarah_fg.priv" | ||
|
||
def test_port_status_check(self): | ||
# ssh port | ||
self.assertFalse(util.check_port_status("google.com")) | ||
# ssh port | ||
self.assertTrue(util.check_port_status("research.cs.colorado.edu")) | ||
# http port | ||
self.assertTrue(util.check_port_status("google.com",80,2)) | ||
# wrong domain | ||
self.assertFalse(util.check_port_status("Idonotexistwallah.wrong")) | ||
# wrong ip | ||
self.assertFalse(util.check_port_status("256.256.256.256")) | ||
|
||
|
||
def test_run_remote_command(self): | ||
result = util.RemoteCommand(self.testing_machine, | ||
self.key_filename, "grep ewrqwerasdfqewr /etc/passwd").execute() | ||
self.assertNotEqual(result,0) | ||
|
||
result = util.RemoteCommand(self.testing_machine, | ||
self.key_filename, "ls -al /etc/passwd").execute() | ||
self.assertEqual(result,0) | ||
|
||
def test_clone_git_repo(self): | ||
self.assertIsNotNone(util.clone_git_repo("https://github.com/alal3177/automaton.git")) | ||
|
||
def test_is_executable(self): | ||
self.assertFalse(util.is_executable_file("wrong/path")) | ||
self.assertTrue(util.is_executable_file("/bin/echo")) | ||
self.assertFalse(util.is_executable_file("/tmp")) | ||
|
||
def test_get_executable_files(self): | ||
self.assertIsNotNone(common.get_executable_files("/bin")) | ||
|
||
if __name__ == '__main__': | ||
unittest.main() |