Forum Discussion
Cannot add 3rd irule to vip due to priority error even if priorities are different
Gurus
I posted this on the pycontrol group already but it's probably more of an icontrol so I'm posting it here again.
https://devcentral.f5.com/community/group/aft/2166035/asg/4
For those not subscribed to the pycontrol group I'm pasting this in here again. Sorry for cross-post.
****************************************************************
I'm trying to use it to dynamically add a maintenance irule and then remove it again based on a ruby script that's out on devcentral.
However, I'm running into a wall finally and it smells like a bug or massively misleading API error to me.
I know that icontrol is stricter than the gui and won't let me add 2 irules with the same priority except I can prove to you that it does anyway whereas I cannot add a 3rd iRule
if 2 exist already no matter what the priorities are.
Case in point. I have a test vs with no irules. I can use my pycontrol script to add a redirect rule no problem.
***********************
SCENARIO 1 (works when it shouldn't) :
[stucky@vito pycontrol]$ ./maintenance.py blablabla
The iRule 'api_maintenance' already existed but got refreshed.
Successfully added iRule 'api_maintenance' to virtual server '/Common/test'
The irule is set to priority 1 :
[root@stglbltm01:Active:Standalone] config tmsh show ltm rule api_maintenance
---------------------------------------------
Ltm::Rule Event: api_maintenance:HTTP_REQUEST
---------------------------------------------
Priority 1
Executions
Now as per docs I should not be able do this again if another rule with pri 1 already exists. To test let's remove this rule again and manually add the test rule with pri 1.
[root@stglbltm01:Active:Standalone] config tmsh list ltm virtual test
ltm virtual test {
destination ip:http
ip-protocol tcp
mask 255.255.255.255
profiles {
http { }
tcp { }
}
rules {
test_hipri
}
[root@stglbltm01:Active:Standalone] config tmsh show ltm rule test_hipri
----------------------------------------
Ltm::Rule Event: test_hipri:HTTP_REQUEST
----------------------------------------
Priority 1
Executions
Ok now let's try to use pycontrol to add the maintenance rule again:
[stucky@vito pycontrol]$ ./maintenance.py blablabla
The iRule 'api_maintenance' already existed but got refreshed.
Successfully added iRule 'api_maintenance' to virtual server '/Common/test'
Let's confirm we have both rules associated with the vs:
[root@stglbltm01:Active:Standalone] config tmsh list ltm virtual test
ltm virtual test {
destination ip:http
ip-protocol tcp
mask 255.255.255.255
profiles {
http { }
tcp { }
}
rules {
test_hipri
api_maintenance
}
Now I don't mind if something works that shouldn't as much as I do when something doesn't work that should !
**************************
SCENARIO 2 (Doesn't work when it really should !!)
Let's add 2 irules to this vs both with DIFFERENT priorities (other than 1 for sure !):
[root@stglbltm01:Active:Standalone] config tmsh list ltm virtual test
ltm virtual test {
destination ip:http
ip-protocol tcp
mask 255.255.255.255
profiles {
http { }
tcp { }
}
rules {
log_persistence_cookie
filter_http_methods
}
We have pri 800 and pri 10.
[root@stglbltm01:Active:Standalone] config tmsh show ltm rule log_persistence_cookie
----------------------------------------------------
Ltm::Rule Event: log_persistence_cookie:HTTP_REQUEST
----------------------------------------------------
Priority 800
Executions
[root@stglbltm01:Active:Standalone] config tmsh show ltm rule filter_http_methods
-------------------------------------------------
Ltm::Rule Event: filter_http_methods:HTTP_REQUEST
-------------------------------------------------
Priority 10
Executions
According to the docs I should have no problem adding a 3rd irule with priority 1 here via pycontrol so let's try :
[stucky@vito pycontrol]$ ./maintenance.py blablab
The iRule 'api_maintenance' already existed but got refreshed.
No handlers could be found for logger "suds.client"
Server raised fault: 'Exception caught in LocalLB::urn:iControl:LocalLB/VirtualServer::add_rule()
Exception: Common::OperationFailed
primary_error_code : 17237537 (0x01070621)
secondary_error_code : 0
error_string : 01070621:3: Rule priorities for virtual server (/Common/test) must be unique.'
This totally hoses me cause I cannot finish my maintenance script testing now. It's all moot if I can't get this rule added/removed on the fly.
Please tell me I'm doing something wrong !
Keep up the great forum !
thx
12 Replies
- Thanks for all the data. You should absolutely be able to add more than 2 iRules to a virtual server. Can you post how you are calling the methods? Are you sure you are passing in the priority correctly in the method parameter?
I've got an example in PowerShell that calls the VirtualServer.add_rule() method at https://devcentral.f5.com/wiki/iControl.PsProvisionVEForLocalDev.ashx Look for the Create-iRule function if that helps. - stucky101_88485
Nimbostratus
Joe
Thanks for looking into this. It may have to do with how I add the irule.
I admit I wasn't able to work it out from the API (sorry I'm new to both icontrol and python) but I found
some code on devcentral and it worked so I figured I needed to do it this way. I have to read up on the type factory stuff
as it seems this is how a lot of calls have to be made now.
Here is the code:
def convert_rule(lb,ruleName,priority):
ruleSequence = lb.LocalLB.VirtualServer.typefactory.create('LocalLB.VirtualServer.VirtualServerRuleSequence')
ruleSet = lb.LocalLB.VirtualServer.typefactory.create('LocalLB.VirtualServer.VirtualServerRule')
ruleSet.rule_name = ruleName
ruleSet.priority = priority
ruleSequence.item = [ruleSet]
return [ruleSequence]try:
lb.LocalLB.VirtualServer.add_rule(virtual_servers = [virtual_server], rules = [convert_rule(lb, maintenance_irule_name, 1)])
print "Successfully added iRule '%s' to virtual server '%s'\n" % (maintenance_irule_name,virtual_server)
except Exception, e:
print e
sys.exit()The maintenance_irule I create on the fly like this :
lines = [" This iRule redirects to the standard maintenance page with the highest priority.\n",
" Generated by pycontrol. Manual edits will be undone.\n",
"priority 1\n",
"when HTTP_REQUEST {\n",
" HTTP::redirect http://mymaintenance_site.html\n",
"}"]
maintenance_irule = ''.join(lines)I first went with the python version of a HERE doc using triple ' but it left the irule with an ugly, undesired indentation that I found no way of removing
so I went with joining list members into string. Seems to work from what I can tell.
I have 2 more questions :
1. Why do I have to pass the priority explicitly when I add the rule when it's already coded into the rules itself ? Maybe this redundancy is causing the problem ?
Where do you recommend I set the priority ? I prefer the irule itself so I can see the priority when looking at the rule in the gui.
2. As per my examples the 2 pre-existing irules had pri 10 and 800 so even if I didn't pass the pri for the 3rd rule it should default to 500 right ?
Still no reason to complain correct ?
- stucky101_88485
Nimbostratus
In case you want to see how I create the irule in the first place...
lines = [" This iRule redirects to the standard maintenance page with the highest priority.\n",
" Generated by pycontrol. Manual edits will be undone.\n",
"priority 1\n",
"when HTTP_REQUEST {\n",
" HTTP::redirect http://webassets.scea.com/generic_maintenance/sceait_generic/maintenance.html\n",
"}"]
maintenance_irule = ''.join(lines)
maintenance_irule_name = 'api_maintenance'
irule_definition = { 'rule_name': maintenance_irule_name,
'rule_definition': maintenance_irule }
If rule already exists refresh it, otherwise create it.
existing_rules = lb.LocalLB.Rule.get_list()
for rule in existing_rules:
if maintenance_irule_name in rule:
pre_exists = True
break
else:
pre_exists = False
if pre_exists is True:
try:
lb.LocalLB.Rule.modify_rule([irule_definition])
print "\nThe iRule '%s' already existed but got refreshed.\n" % maintenance_irule_name
except Exception, e:
print e
sys.exit()
else:
try:
lb.LocalLB.Rule.create([irule_definition])
print "\nThe iRule '%s' was successfully created.\n" % maintenance_irule_name
except Exception, e:
print e
sys.exit() - stucky101_88485
Nimbostratus
Joe
I have some news (good news !)
I realized that pycontrol is already out the window and it's on to bigsuds. I must say bigsuds is an improvement ! I like it. I was able to work out the syntax to add an irule in bigsuds without any helper function:
lb.LocalLB.VirtualServer.add_rule(['/Common/test'], [[{'rule_name':'/Common/api_maintenance', 'priority': 1}]])
The API could use some more clarity here to be honest - I pieced this together and it took longer than it should have but that aside...
However, the same problem persists. Then just for giggles I changed the priority to 2 and guess what ? It works !
It also works with other numbers but as soon as you try 1 again it bails when there are already 2 rules bound.
Bug in the API ?
Not sure I care too much since 2 does the trick just fine assuming nobody created a normal rule with P1.
Wanted to share that... - stucky101_88485
Nimbostratus
To add...can you explain why I need a list that has another list as a single member, this list in turn has one dictionary as a single member.
Sorry I don't get the purpose of the double list context here.
Why is this not enough :
lb.LocalLB.VirtualServer.add_rule(['/Common/test'], [{'rule_name':'/Common/api_maintenance', 'priority': 1}])
thx - Brent_West_7733Historic F5 AccountPosted By stucky101 on 03/02/2013 09:08 PM
Joe
I have some news (good news !)
I realized that pycontrol is already out the window and it's on to bigsuds. I must say bigsuds is an improvement ! I like it. I was able to work out the syntax to add an irule in bigsuds without any helper function:
lb.LocalLB.VirtualServer.add_rule(['/Common/test'], [[{'rule_name':'/Common/api_maintenance', 'priority': 1}]])
The API could use some more clarity here to be honest - I pieced this together and it took longer than it should have but that aside...
However, the same problem persists. Then just for giggles I changed the priority to 2 and guess what ? It works !
It also works with other numbers but as soon as you try 1 again it bails when there are already 2 rules bound.
Bug in the API ?
Not sure I care too much since 2 does the trick just fine assuming nobody created a normal rule with P1.
Wanted to share that...I'll take a stab at this...
Since you already have iRules associated with the virtual server, you can't "insert" a new rule in front of the existing priority order, you must "append" a rule to the end of the list. I believe that when you insert a rule with a priority that is out of range, it reorders the priority to the next available number, so... you could technically add a rule with a priority of 99, and unless you had 99 rules it would append the rule to the end of the list with the next available number.
Additionally, you may be unsatisfied with the results of simply adding a rule to the end of the list. The reason for the priority is that each iRule fires in order, and if there are conflicting results...
i.e. you have two iRules that use when HTTP_REQUEST... both set the destination pool based on a URI... the last rule to fire wins, and could "undo" the results of the lower priority rule.
The correct way to do this, placing the rules in the desired order, would be:
1. "get_rule"
2. modify the rule names and priorities in the resulting array from "get_rule"
3. "remove_all_rules"
4. "add_rule" with the new array from step 2.
As an added safety measure, if you are using BigIP version 11 or higher, you could do all of this within the context of a transaction, that way if any step fails, the entire transaction is rolled back and no modifications are made, leaving your existing rule set intact, for example if you added an invalid rule name or a duplicate priority number. This certainly takes a lot of worry out of the "remove all rules" command!
If you simply want to append an iRule to the end, you would do a "get_rule", progrmatically find the highest priority number, add 1, and then "add_rule" with the correct array syntax. - Brent_West_7733Historic F5 AccountPosted By stucky101 on 03/02/2013 09:12 PM
To add...can you explain why I need a list that has another list as a single member, this list in turn has one dictionary as a single member.
Sorry I don't get the purpose of the double list context here.
Why is this not enough :
lb.LocalLB.VirtualServer.add_rule(['/Common/test'], [{'rule_name':'/Common/api_maintenance', 'priority': 1}])
thxThis has to do with the API works.
The API is designed so that you can have MANY virtuals and add MANY rules in one API call. Even if you are only modifying 1 virtual, and modifying 1 rule at a time, the API expects an array (same as a python list) of virtuals that you want to access and an array(list) of rules you want to add.
If you are creating some hefty tools this approach is much more efficient, but I'll agree that it can be a lot of data structures to keep track of, especially if your goal is a fairly simple 1 to 1 call.
- stucky101_88485
Nimbostratus
Brian
Thank you for your responses.
I confirmed 100% what you stated about rule order. It appears you have to append it and the error just isn't very clear about what it wants.
It appears there are really 2 kinds of priorities (order of listing in the gui and actual coded priority which overwrites the list order afaik)
What I don't understand is why the API cares the least in what order I add any of my rules considering that each rule could have a priority set within it which makes the listing order irrelevant.
I tested this and can confirm it: When I have 5 pre-existing rules and I add my maintenance rule with priority 100 it appends it. Yet the rule itself is actually set to p1.
A quick tmsh show ltm rule {rulename} confirms that the rule is at p1 eventhough it was inserted at p100 so in my mind the p100 just got replaced with a p1 no ?
So given that :
1. I _have_ to append the rule to the end of my rule stack
2. I can set any priority within the rule and it will win
I see no point in the API forcing me to set what appears to be an arbitrary number at rule association time.
As to your other suggestion I did think about that for a bit but I have some issues here:
1. If I remove the current rule set where do I save it ? I'd have to have a way to save state somewhere and then restore it. I assume you mean to save the entire b config on the unit and then restore it once maintenance is over ?
Seems a bit extreme in my opinion. I also wouldn't wanna save something to my desktop from where I'm running bigsuds so I'm a bit unclear how you'd approach that.
2. I simply feel uncomfi making any more changes than I have to especially being very new to icontrol and python so this doesn't feel like the right choice.
3. I don't see why my current solution of appending a P1-coded maint irule to a pre-existing list would not be ok. It works very well so far. In the gui it shows up last but it is reported as P1 under tmsh.
I mean once it's hit it redirects to another site anyway so the other 5 rules don't kick in to begin with so I couldn't care less about them while the site is in maintenance.
Do you see any issues that I'm not ?
thx - Brent_West_7733Historic F5 AccountPosted By stucky101 on 03/03/2013 01:10 AM Brian Thank you for your responses.
I confirmed 100% what you stated about rule order. It appears you have to append it and the error just isn't very clear about what it wants.
It appears there are really 2 kinds of priorities (order of listing in the gui and actual coded priority which overwrites the list order afaik) There is only one priority list, the GUI simply obfuscates it from the user. I think it's important to note here that the BigIP GUI uses iControl; essentially everything that the GUI is showing you was obtained through a very complicated iControl program What I don't understand is why the API cares the least in what order I add any of my rules considering that each rule could have a priority set within it which makes the listing order irrelevant. I tested this and can confirm it: When I have 5 pre-existing rules and I add my maintenance rule with priority 100 it appends it. Yet the rule itself is actually set to p1. A quick tmsh show ltm rule {rulename} confirms that the rule is at p1 eventhough it was inserted at p100 so in my mind the p100 just got replaced with a p1 no ?So given that :
1. I _have_ to append the rule to the end of my rule stack 2. I can set any priority within the rule and it will winI'd have to test that, your experience does seem counter-intuitive. My expectation would be that if you set priority 100 on a virtual with 5 rules, that the priority 100 iRule would become p5 (0 - 4 already existing)
I see no point in the API forcing me to set what appears to be an arbitrary number at rule association time.iRule priorites aren't arbitrary. The list order in the GUI, and the TMSH order from the config are VERY signifigant. iRule processing happens in the order they are shown in both TMSH and in the GUI, The reason the priority order is important, is for the reasons I described in my first reply. In your case, it may not be important, as you are setting up a redirect response, however, if you were doing something like, say.. attempting to control a persistence record or pool declaration in two different iRules, your results may depend on the last iRule that fired (the iRule with the highest priority number).
I'll test the scenario you've given to see if I come up with similar results, if so, then it is something that should be handled within support. If not, I'll see if we can come up with an explanation for what you are seeing.
As to your other suggestion I did think about that for a bit but I have some issues here:1. If I remove the current rule set where do I save it ? I'd have to have a way to save state somewhere and then restore it. I assume you mean to save the entire b config on the unit and then restore it once maintenance is over ?
iControl applications aren't typically interactive in this way. if you were writing an application that uses the BigSuds library (something I don't have a lot of experience with) I would imagine that you would do something like this:
// Please forgive me if my Python syntax is wrong. I am VERY rusty with python... 1. virtualname = '/Common/test' 2. rule_list = lb.LocalLB.VirtualServer.get_rule([virtualname]) //Here we are saving the rule list in a variable to be reused later 3. // This is where you would look for the highest priority order, add the new rule, and change the existing priority orders 4. lb.LocalLB.VirtualServer.remove_all_rules([virtualname]) // This removes the existing rules, so that our new priorties don't conflict with the existing ones 5. b.LocalLB.VirtualServer.add_rule([virtualname],[rule_list]) // Here we are reloading the list that we saved earlier, with the changes you made in step 2.Seems a bit extreme in my opinion. I also wouldn't wanna save something to my desktop from where I'm running bigsuds so I'm a bit unclear how you'd approach that.
2. I simply feel uncomfi making any more changes than I have to especially being very new to icontrol and python so this doesn't feel like the right choice.
3. I don't see why my current solution of appending a P1-coded maint irule to a pre-existing list would not be ok. It works very well so far. In the gui it shows up last but it is reported as P1 under tmsh. I mean once it's hit it redirects to another site anyway so the other 5 rules don't kick in to begin with so I couldn't care less about them while the site is in maintenance.You're solution may be OK for you. I just wanted to call out that this may not be the appropriate solution for every circumstance considering the impact rule priority has on iRules stepping over each other.
The extreme nature of my proposed solution was to identify a way of changing the priority order, if it is neccessary, again, in your case it may not be.
- Brent_West_7733Historic F5 AccountI thought about it a little more, perhaps this what you mean...
If you were to use my code above, without step 2, you would be adding back the list exactly as the API gave it to you, with the same rule names and same priority orders
the results of
rule_list = lb.LocalLB.VirtualServer.get_rule([virtualname])
may look something like this:
{{'rule_name': 'rule_0', 'priority':'0', {'rule_name': 'rule_1', 'priority':'1'}, {'rule_name': 'rule_2', 'priority':'2'}}
The reason that you have to have the 'priority' key in a python dictionary is that when the rule_list dictionary is enumerated by Python, it may return the list to iControl like this:
{{'rule_name': 'rule_2', 'priority':'2'}, {'rule_name': 'rule_0', 'priority':'0'}, {{'rule_name': 'rule_1', 'priority':'1'}}
This is how is inherent in the way Python works. (Perl as well). Associative arrays (Python calls them dictionaries, perl calls them hashes) don't return in the same order that they are stored. You can sort an array(dictionary, list), but the next time you try and recall it, it is again unsorted; it's just the way the underlying coding languages work. Instead of a variable, you could do the same:
lb.LocalLB.VirtualServer.add_rule([virtualname], [{{'rule_name': 'rule_2', 'priority':'2'}, {'rule_name': 'rule_0', 'priority':'0'}, {{'rule_name': 'rule_1', 'priority':'1'}}])
and when I control received it, it would be in a random order, which is why we have to specify the priority number at association time.
Help guide the future of your DevCentral Community!
What tools do you use to collaborate? (1min - anonymous)Recent Discussions
Related Content
* Getting Started on DevCentral
* Community Guidelines
* Community Terms of Use / EULA
* Community Ranking Explained
* Community Resources
* Contact the DevCentral Team
* Update MFA on account.f5.com