Skip to content
This repository was archived by the owner on Jun 9, 2021. It is now read-only.

Commit 5882979

Browse files
authored
Merge pull request #199 from chops77/master
Personal project updates
2 parents b315902 + d6784bb commit 5882979

File tree

2 files changed

+334
-0
lines changed

2 files changed

+334
-0
lines changed

students/Chao/project_fpy/fpy.py

Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
#!/usr/bin/env python
2+
3+
"""
4+
Project Fpy
5+
=================
6+
Po-Sung (Sean) Chao
7+
8+
The purpose of this Python program is to build a maintenance tool with F5 Python SDK
9+
10+
Package required: F5 Python SDK
11+
$ pip install f5-sdk
12+
=================
13+
"""
14+
15+
from f5.bigip import ManagementRoot
16+
from f5.utils.responses.handlers import Stats
17+
from icontrol.exceptions import iControlUnexpectedHTTPError
18+
from requests.exceptions import ConnectionError
19+
import getpass
20+
import ipaddress
21+
22+
class LTM:
23+
""" Main Class for Local Traffic Manager Module """
24+
def __init__(self, mgmt):
25+
self.mgmt = mgmt
26+
27+
class Pool(LTM):
28+
""" Pool class for retrieving pool status """
29+
30+
def get_pool_state(self, p_name, p_partition='Common'):
31+
""" Function to retrieve current pool availability status """
32+
pool_stat = self.mgmt.tm.ltm.pools.pool.load(name=p_name, partition=p_partition)
33+
stats = Stats(pool_stat.stats.load())
34+
return stats.stat.status_availabilityState['description']
35+
36+
def get_pool(self):
37+
""" Pool full status function """
38+
pools = self.mgmt.tm.ltm.pools.get_collection()
39+
print("\n==================== Pool Status ========================")
40+
print("| Pool Name | Partition | Availability |")
41+
for pool in pools:
42+
pstat = self.get_pool_state(pool.name, pool.partition)
43+
print("| {:20} | {:15} | {:12} |".format(pool.name, pool.partition, pstat))
44+
print("=========================================================")
45+
46+
class Virtual(LTM):
47+
""" Virtual class for retrieving virtual server status or modifying config """
48+
49+
def get_virtual_state(self, v_name, v_partition='Common'):
50+
""" Function to retrieve current virtual server availability status """
51+
virtual_stat = self.mgmt.tm.ltm.virtuals.virtual.load(name=v_name, partition=v_partition)
52+
stats = Stats(virtual_stat.stats.load())
53+
return stats.stat.status_availabilityState['description']
54+
55+
def get_virtual(self):
56+
""" Virtual Server full status function """
57+
virtuals = self.mgmt.tm.ltm.virtuals.get_collection()
58+
print("\n=================== Virtual Status ======================")
59+
print("| Virtual Server Name | Partition | Availability |")
60+
for virtual in virtuals:
61+
vstat = self.get_virtual_state(virtual.name, virtual.partition)
62+
print("| {:20} | {:15} | {:12} |".format(virtual.name, virtual.partition, vstat))
63+
print("=========================================================")
64+
65+
def apply_rule(self, myrule='fpy_maintenace'):
66+
""" iRule apply function """
67+
virtuals = self.mgmt.tm.ltm.virtuals.get_collection()
68+
for virtual in virtuals:
69+
# set full iRule path
70+
rule_path = '/{}/{}'.format(virtual.partition, myrule)
71+
vrule = self.mgmt.tm.ltm.virtuals.virtual.load(name=virtual.name, partition=virtual.partition)
72+
try:
73+
if rule_path in vrule.rules:
74+
print("Rule {} already exists in {}".format(myrule, virtual.name))
75+
else:
76+
# Insert iRule at the front of the list
77+
vrule.rules.insert(0, rule_path)
78+
vrule.update()
79+
print("Rule {} added to {}".format(myrule, virtual.name))
80+
except iControlUnexpectedHTTPError:
81+
print("Unable to apply rule {} to {}. HTTP profile required.".format(myrule, virtual.name))
82+
83+
def remove_rule(self, myrule='fpy_maintenace'):
84+
""" iRule removal function """
85+
virtuals = self.mgmt.tm.ltm.virtuals.get_collection()
86+
for virtual in virtuals:
87+
rule_path = '/{}/{}'.format(virtual.partition, myrule)
88+
vrule = self.mgmt.tm.ltm.virtuals.virtual.load(name=virtual.name, partition=virtual.partition)
89+
if rule_path in vrule.rules:
90+
vrule.rules.remove(rule_path)
91+
vrule.update()
92+
print("Rule {} removed from {}".format(myrule, virtual.name))
93+
else:
94+
print("Rule {} does not exist in {}".format(myrule, virtual.name))
95+
96+
class Rule(LTM):
97+
""" Rule class for iRule functions """
98+
99+
def get_rule(self):
100+
""" Function for retireving iRule list """
101+
rules = self.mgmt.tm.ltm.rules.get_collection()
102+
print("\n======================== iRule List ======================")
103+
print("| iRule Name | Partition |")
104+
for rule in rules:
105+
print("| {:40} | {:11} |".format(rule.name, rule.partition))
106+
print("==========================================================")
107+
108+
def create_rule(self, myrule='fpy_maintenace'):
109+
""" Create a maintenance iRule """
110+
if self.mgmt.tm.ltm.rules.rule.exists(name=myrule, partition='Common'):
111+
result = input("\nExisting iRule {}. Do you want to overwrite? ('y' or 'yes'): ".format(myrule))
112+
if result == 'y' or result == 'yes':
113+
# Modify the iRule
114+
mrule = self.mgmt.tm.ltm.rules.rule.load(name=myrule, partition='Common')
115+
mrule.modify(apiAnonymous="when HTTP_REQUEST {\nHTTP::respond 200 content {\n<!DOCTYPE html>\n<title>Site under Maintenance</title>\n}\n}")
116+
print("\niRule {} modified.".format(myrule))
117+
else:
118+
print("\nNo iRule modification was made.")
119+
else:
120+
# Create new iRule
121+
mrule = self.mgmt.tm.ltm.rules.rule.create(name=myrule, partition='Common', apiAnonymous="when HTTP_REQUEST {\nHTTP::respond 200 content {\n<!DOCTYPE html>\n<title>Site under Maintenance</title>\n}\n}")
122+
print("\niRule {} created.".format(myrule))
123+
124+
def check_rule(self, myrule, mypar='Common'):
125+
""" Simple function to check if certain iRule already exists """
126+
return self.mgmt.tm.ltm.rules.rule.exists(name=myrule, partition=mypar)
127+
128+
129+
def display(mgmt):
130+
""" Submenu for display menu """
131+
while True:
132+
print("\n================ Display Menu =================")
133+
print("* (1) Pool Status *")
134+
print("* (2) Virtual Server Status *")
135+
print("* (3) iRule List *")
136+
print("* (q) Retuen to Main Menu *")
137+
print("===============================================")
138+
139+
result = input("Please select a menu item: ")
140+
141+
if result == '1':
142+
p = Pool(mgmt)
143+
p.get_pool()
144+
elif result == '2':
145+
v = Virtual(mgmt)
146+
v.get_virtual()
147+
elif result == '3':
148+
r = Rule(mgmt)
149+
r.get_rule()
150+
elif result == 'q':
151+
break
152+
else:
153+
print("\n*** Selected item not in the menu. Please try again. ***")
154+
155+
def maintenance(mgmt):
156+
""" Submenu for maintenance menu """
157+
while True:
158+
print("\n================= Maintenance Menu ===================")
159+
print("* (1) Create Maintenance iRule *")
160+
print("* (2) Apply Maintenance iRule to All VIPs *")
161+
print("* (3) Remove Maintenance iRule from All VIPs *")
162+
print("* (q) Retuen to Main Menu *")
163+
print("======================================================")
164+
165+
result = input("Please select a menu item: ")
166+
167+
if result == '1':
168+
r = Rule(mgmt)
169+
rule_name = input("Please enter iRule name (optioanl): ")
170+
if rule_name:
171+
r.create_rule(rule_name)
172+
else:
173+
r.create_rule()
174+
elif result == '2':
175+
v = Virtual(mgmt)
176+
r = Rule(mgmt)
177+
rule_name = input("Please enter iRule you want to apply (default=fpy_maintenace): ")
178+
if rule_name:
179+
if r.check_rule(rule_name):
180+
# Call apply_rule function only when it exists
181+
v.apply_rule(rule_name)
182+
else:
183+
print("iRule {} does not exist.".format(rule_name))
184+
else:
185+
v.apply_rule()
186+
elif result == '3':
187+
v = Virtual(mgmt)
188+
r = Rule(mgmt)
189+
rule_name = input("Please enter iRule you want to remove (default=fpy_maintenace): ")
190+
if rule_name:
191+
if r.check_rule(rule_name):
192+
v.remove_rule(rule_name)
193+
else:
194+
print("iRule {} does not exist.".format(rule_name))
195+
else:
196+
v.remove_rule()
197+
elif result == 'q':
198+
break
199+
else:
200+
print("\n*** Selected item not in the menu. Please try again. ***")
201+
202+
203+
def login():
204+
""" Login handling function """
205+
206+
ip = input("Please enter the IP address of the Big-IP system: ")
207+
try:
208+
# Make sure the user uses current ip format
209+
ipaddress.ip_address(ip)
210+
except ValueError:
211+
print("\nWrong IP format. Please enter a valid IP address.")
212+
quit()
213+
214+
user = input("Username: ")
215+
# Hide user password
216+
pw = getpass.getpass("Password: ")
217+
try:
218+
# Return the Managemen object
219+
return ManagementRoot(ip, user, pw)
220+
except iControlUnexpectedHTTPError:
221+
print("\nInvalid login, please verify your credential and try again.")
222+
quit()
223+
except ConnectionError:
224+
print("\nUnable to connect to " + ip)
225+
quit()
226+
227+
def main_loop():
228+
""" Main menu to call submenu """
229+
230+
# Call login functions
231+
mgmt = login()
232+
print("\nLogged in successful, Big-IP version: " + mgmt.tmos_version)
233+
234+
menu_dict = {'1': display, '2': maintenance, 'q': quit}
235+
236+
while True:
237+
print("\n===================== Fpy Main Menu ======================")
238+
print("* (1) Display Current Objects *")
239+
print("* (2) Maintenance Menu *")
240+
print("* (q) Quit *")
241+
print("==========================================================")
242+
result = input("Please select a menu item: ")
243+
if result == 'q':
244+
menu_dict[result]()
245+
else:
246+
try:
247+
menu_dict[result](mgmt)
248+
except KeyError:
249+
print("\n*** Selected item not in the menu. Please try again. ***")
250+
251+
if __name__ == '__main__':
252+
""" Main function """
253+
main_loop()
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
#!/usr/bin/env python
2+
3+
"""
4+
Unit test for classes in fpy program
5+
"""
6+
7+
from f5.bigip import ManagementRoot
8+
import fpy
9+
import pytest
10+
11+
# Connect to the test unit. Credential will be sanitized after test.
12+
mgmt = ManagementRoot("1.1.1.1", "admin", "password")
13+
14+
def test_LTM_init():
15+
""" LTM object initialization test """
16+
l = fpy.LTM(mgmt)
17+
assert l.mgmt.tmos_version == '12.1.1'
18+
19+
def test_get_pool_state():
20+
""" Test get_pool_state function """
21+
p = fpy.Pool(mgmt)
22+
assert p.get_pool_state('sipp') == 'unknown'
23+
assert p.get_pool_state('p1p1', 'p1') == 'offline'
24+
25+
def test_get_pool(capfd):
26+
""" Test get_pool function """
27+
p = fpy.Pool(mgmt)
28+
p.get_pool()
29+
out, err = capfd.readouterr()
30+
assert 'Pool Status' in out
31+
32+
def test_get_virtual_state():
33+
""" Test get_virtual_state function """
34+
v = fpy.Virtual(mgmt)
35+
assert v.get_virtual_state('main_test') == 'unknown'
36+
37+
def test_get_virtual(capfd):
38+
""" Test get_virtual function """
39+
v = fpy.Virtual(mgmt)
40+
v.get_virtual()
41+
out, err = capfd.readouterr()
42+
assert 'Virtual Status' in out
43+
44+
def test_apply_rule(capfd):
45+
""" Test apply rule function """
46+
v = fpy.Virtual(mgmt)
47+
v.apply_rule('test_rule')
48+
out, err = capfd.readouterr()
49+
assert 'HTTP profile required' in out
50+
51+
def test_remove_rule(capfd):
52+
""" Test remove rule function """
53+
v = fpy.Virtual(mgmt)
54+
v.remove_rule('test_rule')
55+
out, err = capfd.readouterr()
56+
assert 'removed' in out
57+
58+
def test_get_rule(capfd):
59+
""" Test get rule function """
60+
r = fpy.Rule(mgmt)
61+
r.get_rule()
62+
out, err = capfd.readouterr()
63+
assert 'iRule List' in out
64+
65+
def test_create_rule():
66+
""" Test create rule function """
67+
r = fpy.Rule(mgmt)
68+
r.create_rule('test_rule_2')
69+
assert mgmt.tm.ltm.rules.rule.exists(name='test_rule_2', partition='Common')
70+
71+
def test_creat_rule2(capfd):
72+
""" Test create rule output function """
73+
r = fpy.Rule(mgmt)
74+
r.create_rule('test_rule_3')
75+
out, err = capfd.readouterr()
76+
assert 'created' in out
77+
78+
def test_check_rule():
79+
""" Test check rule function """
80+
r = fpy.Rule(mgmt)
81+
assert r.check_rule('test_rule')

0 commit comments

Comments
 (0)