Writing a RAID Calculator in Python

RAIDr is a RAID calculator written in python. It accepts input from the user and calculates how a certain configuration of hard drives will be allocated across different RAID configurations. This is the first program I ever wrote and the project that got me interested in programming. It’s not the most efficient, and there are some alternate ways to approach this problem, but I’m happy with the product as it turned out. It is still incomplete, but hopefully, someone can find it useful. The code is commented with thoughts on how it should function and things that need to be done. I’m not a professional python programmer, and my methodology might not be completely “pythonic”, but this was a great project for me to gain exposure to programming and syntactical logic. Any constructive criticism is welcomed.

</pre>
## Josh Dean
## RAIDr
## Created: 2/14/2017
## Last Edit: 3/21/2017
## Known bugs:

## Global Declarations

hddnumvar = 0
hddsizevar = 0
raidvar = 0
hddwritevar = 0 ## used to mitigate reference error in RAID 10 calculation

## Functions

def hdd_num():
	global hddnumvar
	print ("\nHow many drives are in the array?") ## eventual formatting errors will come from here
	hddnumvar = input() ## necessary if variable is global?
	if hddnumvar == 1:
		print ("Error: Can't create a RAID with 1 disk.")
		hdd_num()
	elif hddnumvar &gt; 1:
		print hddnumvar, "drives in the array"
		print "----------------------- \n"
	else:
		print ("I don't know what you entered but it's incorrect.")

def hdd_size(): ##needs error parsing
	global hddsizevar
	print ("What is the capacity of the drives? (gigabyte)")
	hddsizevar = input() ## possible to use line break with input
	print hddsizevar, "raw GiB per disk"
	print "----------------------- \n"
	print("%s drives in the array of %s GiB each.") % (hddnumvar, hddsizevar) ##there was a return value here, implication, seems to be hanging here with a syntax error?
	##removed the % format for something else, seems to be working single quotations critical for functional syntax, fixed it by including the arguments in parathesis
	raid_prompt()

def raid_prompt(): ##update this to reflect actual raid configurations, calls raid_calculation, all edits and calls should start here
	print ("\n1 - RAID 0")
	print ("2 - RAID 1")
	print ("3 - RAID 5")
	print ("4 - RAID 5E")
	print ("5 - RAID 5EE")
	print ("6 - RAID 6")
	print ("7 - RAID 10")
	print ("8 - RAID 50")
	print ("9 - RAID 60 \n")
	raidvar = input("What raid configuration? \n")
	raid_calculation(raidvar)

def raid_calculation(raidvar): ## just handles the menu
	if raidvar == 1:
		hddtotal = hddsizevar * hddnumvar ## variables need to go first
		print "\n-----------------------" ## /n doesn't need a space to seperate, bad formatting, best to put this in front
		print ("RAID 0 - Striped Volume")
		print hddnumvar, "drives in the array"
		print hddsizevar, "raw GiB in the array per disk"
		print "%s raw GiB in the array total" % hddtotal
		print "Total of", hddnumvar * hddsizevar, "GiB in the RAID array." ## this need alternative wording throughout the program
		print "%s times write speed" % hddnumvar ## Can I put these two prints on one line? Multiple % variables?
		print "%s times read speed" % hddnumvar
		print "No redundancy"
		print "No hot spare"
		print "----------------------- \n"
	elif raidvar == 2:
		print "\n-----------------------"
		print ("RAID 1 - Mirrored Volume")
		print hddnumvar, "drives in the array"
		print hddsizevar, "raw GiB per disk"
		print "Total of", hddsizevar, "GiB in the array."
		print "%s times read speed" % hddnumvar
		print "No write speed increase"
		hddredunvar = hddnumvar - 1
		print "%s disk redundancy" % hddredunvar
		print "No hot spare"
		print "----------------------- \n"
	elif raidvar == 3:
		if hddnumvar &lt; 3:
			print &quot;\nYou need at least 3 disks to utilize Raid 5&quot;
			disk_num_prompt()
		else:
			print &quot;\n-----------------------&quot;
			print (&quot;RAID 5 - Parity&quot;)
			print hddnumvar, &quot;drives in the array&quot;
			print hddsizevar, &quot;raw GiB per disk&quot;
			print &quot;Total of&quot;, (hddnumvar - 1) * hddsizevar, &quot;GiB in the array.&quot;
			hddreadvar = hddnumvar - 1
			print &quot;%s times read speed&quot; % hddreadvar
			print &quot;No write speed increase&quot;
			print &quot;1 disk redundancy&quot;
			print &quot;No hot spare&quot;
			print &quot;----------------------- \n&quot;
	elif raidvar == 4:
		if hddnumvar &lt; 4:
			print &quot;\nYou need at least 4 disks to utilize RAID 5E\n&quot;
			disk_num_prompt()
		else:
			print &quot;\n-----------------------&quot;
			print (&quot;RAID 5E - Parity + Spare&quot;)
			print hddnumvar, &quot;drives in the array&quot;
			print hddsizevar, &quot;raw GiB per disk&quot;
			print &quot;Total of&quot;, (hddnumvar - 2) * hddsizevar, &quot;GiB in the array.&quot;
			hddreadvar = hddnumvar - 1
			print &quot;%s times read speed&quot; % hddreadvar
			print &quot;No write speed increase&quot;
			print &quot;1 disk redundancy&quot;
			print &quot;1 hot spare&quot;
			print &quot;----------------------- \n&quot;
	elif raidvar == 5:
		if hddnumvar &lt; 4:
			print &quot;\nYou need at least 4 disks to utilize RAID 5EE\n&quot;
			disk_num_prompt()
		else:
			print &quot;\n-----------------------&quot;
			print (&quot;RAID 5EE - Parity + Spare&quot;)
			print hddnumvar, &quot;drives in the array&quot;
			print hddsizevar, &quot;raw GiB per disk&quot;
			print &quot;Total of&quot;, (hddnumvar - 2) * hddsizevar, &quot;GiB in the array.&quot;
			hddreadvar = hddnumvar - 2
			print &quot;%s times read speed&quot; % hddreadvar
			print &quot;No write speed increase&quot;
			print &quot;1 disk redundancy&quot;
			print &quot;2 hot spare&quot;
			print &quot;----------------------- \n&quot;
	elif raidvar == 6:
		if hddnumvar &lt; 4:
			print &quot;\nYou need at least 4 disks to utilize RAID 6\n&quot;
			disk_num_prompt()
		else:
			print &quot;\n-----------------------&quot;
			print (&quot;RAID 6 - Double Parity&quot;)
			print hddnumvar, &quot;drives in the array&quot;
			print hddsizevar, &quot;raw GiB per disk&quot;
			print &quot;Total of&quot;, (hddnumvar - 2) * hddsizevar, &quot;GiB in the array.&quot;
			hddreadvar = hddnumvar - 2
			print &quot;%s times read speed&quot; % hddreadvar
			print &quot;No write speed increase&quot;
			print &quot;2 disk redundancy&quot;
			print &quot;No hot spare&quot;
			print &quot;----------------------- \n&quot;
	elif raidvar == 7:
		if hddnumvar &lt; 4:
			print &quot;\nYou need at least 4 disks to utilize RAID 10\n&quot;
			disk_num_prompt()
		elif (hddnumvar % 2 == 1):
			print &quot;\nYou need an even number of disks to utilize RAID 10\n&quot;
			disk_num_prompt()
		else:
			print &quot;\n-----------------------&quot;
			print (&quot;RAID 10 - Stripe + Mirror&quot;)
			print hddnumvar, &quot;drives in the array&quot;
			print hddsizevar, &quot;raw GiB per disk&quot;
			print &quot;Total of&quot;, (hddnumvar / 2) * hddsizevar, &quot;GiB in the array.&quot;
			hddreadvar = hddnumvar / 2 ## actual write variable calculation
			print &quot;%s times read speed&quot; % hddnumvar
			print &quot;%s write speed increase&quot; % hddreadvar
			print &quot;At least 1 disk redundancy&quot;
			print &quot;No hot spare&quot;
			print &quot;----------------------- \n&quot;
	elif raidvar == 8: ## bookmark, need formulas
		if hddnumvar &lt; 6:
			print &quot;\nYou need at least 6 disks to utilize RAID 50\n&quot;
			disk_num_prompt()
		else:
			print &quot;\n-----------------------&quot;
			print (&quot;RAID 50 - Parity + Stripe&quot;)
			print hddnumvar, &quot;drives in the array&quot;
			print hddsizevar, &quot;raw GiB per disk&quot;
			print &quot;Total of&quot;, (hddnumvar - 2) * hddsizevar, &quot;GiB in the array.&quot;
			hddreadvar = hddnumvar - 2
			##print &quot;%s times read speed&quot; % hddreadvar
			##print &quot;No write speed increase&quot; # Although overall read/write performance is highly dependent on a number of factors, RAID 50 should provide better write performance than RAID 5 alone.
			print &quot;2 disk redundancy&quot;
			print &quot;No hot spare&quot;
			print &quot;----------------------- \n&quot;
	elif raidvar == 9:
		if hddnumvar  9:
		print ("Error: Please select a number between 1 and 9")
		raid_prompt()
	elif raidvar == 0: ## additional error parsing required here
		print ("Error: Please select a number between 1 and 9")
		menu_prompt() ## ubiquitous for all loop items that aren't errors

def disk_num_prompt(): ## this will eventually need to except arguments that are context sensitive for raid type and disk requirements, perhaps handle this is the raid_calculator function
	global hddnumvar
	print "Adjust number of disks?"
	print "1 - Yes"
	print "2 - No"
	disknummenuvar = input()
	if disknummenuvar == 1:
		hddnumvar = input("\nHow many drives are in the array? \n")
		if hddnumvar == 1:
			print "Error: Can't create a RAID with 1 disk."
			hdd_num()
		elif hddnumvar &gt; 1:
			print "\nUpdated"
			print hddnumvar, "drives in the array" ## displays once for every loop, hdd_num_input for mitigation
			raid_prompt()
		else:
			print ("I don't know what you entered but it's incorrect.")
			disk_num_prompt()
	elif disknummenuvar == 2:
		raid_prompt()
	else:
		print("I don't know what you entered but it's incorrect.")
		disk_num_prompt()

#below is the menu for the end of the selected operations
def menu_prompt(): ## need additional option to go to GiB to GB converter?
	print "1 - RAID menu"
	print "2 - Quit"
	print "3 - Start Over"
	menu = input()
	if menu == 1:
		raid_prompt() ## looping, quit() function is ending script, will need revision
	elif menu == 2:
		print "Cya"
		quit()
	elif menu == 3:
		start()
	elif menu == 0:
		print "Error: Please select 1, 2, or 3 \n"
		menu_prompt()
	elif menu &gt; 3:
		print "Error: Please select 1, 2, or 3 \n"
		menu_prompt()
	else:
		print "quit fucking around" ##formatting

def data_transfer_jumpoff(): ##BOOKMARK
	print "What is the transfer speed? Gigabytes, please"
	transfervar = input()
	print"What denominator of data size?"
	print"1 - byte"
	print"2 - kilobyte"
	print"3 - megabyte"
	print"4 - gigiabyte"
	print"5 - terabyte"
	transferunit = input()
	print"How much data?"
	transferamount = input()

## Start Prompt, this needs to be expanded upon
def start(): ##easier way to reset all these variables?
	startmenu = 0
	raid_var = 0 ## should be an inline solution for this in its own function, it just works
	hddnumvar = 0
	hddsizevar = 0
	raidvar = 0
	print("\nChoose an operation") ## line break might cause formatting errors look here first
	print "1 - RAID calculator"
	print "2 - Data Transfer Calculator"
	startmenu = input()
	if startmenu == 1:
		hdd_num() ## these need to be called in a more functional manner
		hdd_size()
	elif startmenu == 2:
		data_transfer_jumpoff()
	else:
		print "Not supported\n" ## will require edit
		start()

#main scripting

start()

 

The operation of the program begins by calling the start functions. I put this function call at the bottom of the script so it would be easily accessible. start() is the last function before the initial start call. From this menu the user is asked which of two currently implemented operations they wish to perform: RAID calculator or Data Transfer Calculator. Data Transfer Calculator is still a work in progress.

system-hdd-raid.jpg

 

When RAID calculator is selected the user is queried about the number of hard drives and their capacity through the calling of two functions: hddnum and hddsize. These functions would be called upon several times during the session of the program, so I thought it would be appropriate to make them their own functions. These functions read input from the users and set the appropriate variables for use during the calculation.

Next the RAID formats available are listed, one of which the user can choose which calculation they want to perform on the previously set variables. In this instance of the code, RAID 1 through 10 work fine, but the functions for RAID 50 and 60 are missing their capacity calculations since the formulas are not as straightforward. Once the selection is made, the results of the calculations are displayed.

At the end of the operation, users are presented with several options. They can change the variables and recalculate. The RAID calculation itself could be changed. The main menu can also be called in the future to perform a data transfer calculation. In the future, it might be beneficial to pass the size of the array, and allow the calculation of the transfer speed by just asking the user for the connection speed. This data could be appended to the RAID data. It might also be beneficial to include a memory function to remember specific RAID configurations, and read it to a text file than can be loaded on subsequent runs.

Another function that might be useful is the reconciliation of GiB values and GB values. This would help if users are using an NTFS file system. It might also be useful to include other filesystem types in the calculations to get the most accurate numbers possible and maximum compatibility.

Again, this was fun to make and I find myself using it from time to time. There is still a lot of work to do if the program can stand on it’s own. Taking user input comes with an interesting set of problems that could allow certain inputs to change the functions of the program. If the user isn’t intentionally trying to break the program this shouldn’t be an issue, the instructions and commands are very clear when user input is necessary. There is some formulaic work to be done with the two newest RAID formats.

Python was a great language for me to grasp the beginning intricacies of programming. I feel like the capability to make even more intricate programs is possible. Combining the operating structure of something like RAIDr with GIS functions illustrated below would allow easy semi-automatic scripting of tasks. The sky is once again the limit.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s