@@ -481,6 +481,50 @@ func (f5 *f5LTM) delete(url string, result interface{}) error {
481
481
return f5 .restRequest ("DELETE" , url , nil , result )
482
482
}
483
483
484
+ //
485
+ // iControl REST resource helper methods.
486
+ //
487
+
488
+ // encodeiControlUriPathComponent returns an encoded resource path for use
489
+ // in the URI for the iControl REST calls.
490
+ // For example for a path /Common/foo, the corresponding encoded iControl
491
+ // URI path component would be ~Common~foo and this can then be used in the
492
+ // iControl REST calls ala:
493
+ // https://<ip>:<port>/mgmt/tm/ltm/policy/~Common~foo/rules
494
+ func encodeiControlUriPathComponent (pathName string ) string {
495
+ return strings .Replace (pathName , "/" , "~" , - 1 )
496
+ }
497
+
498
+ // iControlUriResourceId returns an encoded resource id (resource path
499
+ // including the partition), which can be used the iControl REST calls.
500
+ // For example, for a policy named openshift_secure_routes policy in the
501
+ // /Common partition, the encoded resource id would be:
502
+ // ~Common~openshift_secure_routes
503
+ // which can then be used as a resource specifier in the URI ala:
504
+ // https://<ip>:<port>/mgmt/tm/ltm/policy/~Common~openshift_secure_routes/rules
505
+ func (f5 * f5LTM ) iControlUriResourceId (resourceName string ) string {
506
+ resourcePath := path .Join (f5 .partitionPath , resourceName )
507
+ return encodeiControlUriPathComponent (resourcePath )
508
+ }
509
+
510
+ // iControlUriVserverId returns an encoded Virtual Server id (virtual
511
+ // server name including the partition), which can be used in the iControl
512
+ // REST calls.
513
+ // For example, for a virtual server named ose-vserver in
514
+ // the /rht/ose3/config partition path, the encoded Virtual Server id is:
515
+ // ~rht~ose-vserver
516
+ func (f5 * f5LTM ) iControlUriVserverId (vserverName string ) string {
517
+ // Note: Most resources are stored under the configured partition
518
+ // path, which may be a top-level folder or a sub-folder.
519
+ // However a virtual server can only be stored under a
520
+ // top-level folder.
521
+ // Example: For a vserver named ose-server in the /rht/ose3/config
522
+ // partition path, the encoded URI path component is:
523
+ // ~rht~ose-vserver
524
+ pathComponents := strings .Split (f5 .partitionPath , "/" )
525
+ return encodeiControlUriPathComponent (path .Join ("/" , pathComponents [1 ], vserverName ))
526
+ }
527
+
484
528
//
485
529
// Routines for controlling F5.
486
530
//
@@ -532,7 +576,7 @@ func (f5 *f5LTM) ensureVxLANTunnel() error {
532
576
AddressSource : "from-user" ,
533
577
Floating : "disabled" ,
534
578
InheritedTrafficGroup : "false" ,
535
- TrafficGroup : path .Join (f5 . partitionPath , "traffic-group-local-only" ),
579
+ TrafficGroup : path .Join ("/Common" , "traffic-group-local-only" ), // Traffic group is global
536
580
Unit : 0 ,
537
581
Vlan : path .Join (f5 .partitionPath , F5VxLANTunnelName ),
538
582
AllowService : "all" ,
@@ -552,8 +596,9 @@ func (f5 *f5LTM) ensureVxLANTunnel() error {
552
596
func (f5 * f5LTM ) ensurePolicyExists (policyName string ) error {
553
597
glog .V (4 ).Infof ("Checking whether policy %s exists..." , policyName )
554
598
599
+ policyResourceId := f5 .iControlUriResourceId (policyName )
555
600
policyUrl := fmt .Sprintf ("https://%s/mgmt/tm/ltm/policy/%s" ,
556
- f5 .host , policyName )
601
+ f5 .host , policyResourceId )
557
602
558
603
err := f5 .get (policyUrl , nil )
559
604
if err != nil && err .(F5Error ).httpStatusCode != 404 {
@@ -570,11 +615,13 @@ func (f5 *f5LTM) ensurePolicyExists(policyName string) error {
570
615
571
616
policiesUrl := fmt .Sprintf ("https://%s/mgmt/tm/ltm/policy" , f5 .host )
572
617
618
+ policyPath := path .Join (f5 .partitionPath , policyName )
619
+
573
620
if f5 .setupOSDNVxLAN {
574
621
// if vxlan needs to be setup, it will only happen
575
622
// with ver12, for which we need to use a different payload
576
623
policyPayload := f5Ver12Policy {
577
- Name : policyName ,
624
+ Name : policyPath ,
578
625
TmPartition : f5 .partitionPath ,
579
626
Controls : []string {"forwarding" },
580
627
Requires : []string {"http" },
@@ -584,10 +631,11 @@ func (f5 *f5LTM) ensurePolicyExists(policyName string) error {
584
631
err = f5 .post (policiesUrl , policyPayload , nil )
585
632
} else {
586
633
policyPayload := f5Policy {
587
- Name : policyName ,
588
- Controls : []string {"forwarding" },
589
- Requires : []string {"http" },
590
- Strategy : "best-match" ,
634
+ Name : policyPath ,
635
+ Partition : f5 .partitionPath ,
636
+ Controls : []string {"forwarding" },
637
+ Requires : []string {"http" },
638
+ Strategy : "best-match" ,
591
639
}
592
640
err = f5 .post (policiesUrl , policyPayload , nil )
593
641
}
@@ -602,7 +650,7 @@ func (f5 *f5LTM) ensurePolicyExists(policyName string) error {
602
650
glog .V (4 ).Infof ("Policy %s created. Adding no-op rule..." , policyName )
603
651
604
652
rulesUrl := fmt .Sprintf ("https://%s/mgmt/tm/ltm/policy/%s/rules" ,
605
- f5 .host , policyName )
653
+ f5 .host , policyResourceId )
606
654
607
655
rulesPayload := f5Rule {
608
656
Name : "default_noop" ,
@@ -624,11 +672,13 @@ func (f5 *f5LTM) ensureVserverHasPolicy(vserverName, policyName string) error {
624
672
glog .V (4 ).Infof ("Checking whether vserver %s has policy %s..." ,
625
673
vserverName , policyName )
626
674
675
+ vserverResourceId := f5 .iControlUriVserverId (vserverName )
676
+
627
677
// We could use fmt.Sprintf("https://%s/mgmt/tm/ltm/virtual/%s/policies/%s",
628
- // f5.host, vserverName , policyName) here, except that F5 iControl REST
629
- // returns a 200 even if the policy does not exist.
678
+ // f5.host, vserverResourceId , policyName) here, except that F5
679
+ // iControl REST returns a 200 even if the policy does not exist.
630
680
vserverPoliciesUrl := fmt .Sprintf ("https://%s/mgmt/tm/ltm/virtual/%s/policies" ,
631
- f5 .host , vserverName )
681
+ f5 .host , vserverResourceId )
632
682
633
683
res := f5VserverPolicies {}
634
684
@@ -637,8 +687,10 @@ func (f5 *f5LTM) ensureVserverHasPolicy(vserverName, policyName string) error {
637
687
return err
638
688
}
639
689
690
+ policyPath := path .Join (f5 .partitionPath , policyName )
691
+
640
692
for _ , policy := range res .Policies {
641
- if policy .Name == policyName {
693
+ if policy .FullPath == policyPath {
642
694
glog .V (4 ).Infof ("Vserver %s has policy %s associated with it;" +
643
695
" nothing to do." , vserverName , policyName )
644
696
return nil
@@ -648,7 +700,8 @@ func (f5 *f5LTM) ensureVserverHasPolicy(vserverName, policyName string) error {
648
700
glog .V (4 ).Infof ("Adding policy %s to vserver %s..." , policyName , vserverName )
649
701
650
702
vserverPoliciesPayload := f5VserverPolicy {
651
- Name : policyName ,
703
+ Name : policyPath ,
704
+ Partition : f5 .partitionPath ,
652
705
}
653
706
654
707
err = f5 .post (vserverPoliciesUrl , vserverPoliciesPayload , nil )
@@ -709,7 +762,8 @@ func (f5 *f5LTM) ensureDatagroupExists(datagroupName string) error {
709
762
func (f5 * f5LTM ) ensureIRuleExists (iRuleName , iRule string ) error {
710
763
glog .V (4 ).Infof ("Checking whether iRule %s exists..." , iRuleName )
711
764
712
- iRuleUrl := fmt .Sprintf ("https://%s/mgmt/tm/ltm/rule/%s" , f5 .host , iRuleName )
765
+ iRuleUrl := fmt .Sprintf ("https://%s/mgmt/tm/ltm/rule/%s" , f5 .host ,
766
+ f5 .iControlUriResourceId (iRuleName ))
713
767
714
768
err := f5 .get (iRuleUrl , nil )
715
769
if err != nil && err .(F5Error ).httpStatusCode != 404 {
@@ -727,8 +781,9 @@ func (f5 *f5LTM) ensureIRuleExists(iRuleName, iRule string) error {
727
781
iRulesUrl := fmt .Sprintf ("https://%s/mgmt/tm/ltm/rule" , f5 .host )
728
782
729
783
iRulePayload := f5IRule {
730
- Name : iRuleName ,
731
- Code : iRule ,
784
+ Name : iRuleName ,
785
+ Partition : f5 .partitionPath ,
786
+ Code : iRule ,
732
787
}
733
788
734
789
err = f5 .post (iRulesUrl , iRulePayload , nil )
@@ -748,7 +803,7 @@ func (f5 *f5LTM) ensureVserverHasIRule(vserverName, iRuleName string) error {
748
803
vserverName , iRuleName )
749
804
750
805
vserverUrl := fmt .Sprintf ("https://%s/mgmt/tm/ltm/virtual/%s" ,
751
- f5 .host , vserverName )
806
+ f5 .host , f5 . iControlUriVserverId ( vserverName ) )
752
807
753
808
res := f5VserverIRules {}
754
809
@@ -757,7 +812,7 @@ func (f5 *f5LTM) ensureVserverHasIRule(vserverName, iRuleName string) error {
757
812
return err
758
813
}
759
814
760
- commonIRuleName := fmt . Sprintf ( "%s/%s " , f5 .partitionPath , iRuleName )
815
+ commonIRuleName := path . Join ( "/ " , f5 .partitionPath , iRuleName )
761
816
762
817
for _ , name := range res .Rules {
763
818
if name == commonIRuleName {
@@ -770,8 +825,9 @@ func (f5 *f5LTM) ensureVserverHasIRule(vserverName, iRuleName string) error {
770
825
771
826
glog .V (4 ).Infof ("Adding iRule %s to vserver %s..." , iRuleName , vserverName )
772
827
828
+ sslPassthroughIRulePath := path .Join (f5 .partitionPath , sslPassthroughIRuleName )
773
829
vserverRulesPayload := f5VserverIRules {
774
- Rules : []string {sslPassthroughIRuleName },
830
+ Rules : []string {sslPassthroughIRulePath },
775
831
}
776
832
777
833
err = f5 .patch (vserverUrl , vserverRulesPayload , nil )
@@ -788,10 +844,8 @@ func (f5 *f5LTM) ensureVserverHasIRule(vserverName, iRuleName string) error {
788
844
func (f5 * f5LTM ) checkPartitionPathExists (pathName string ) (bool , error ) {
789
845
glog .V (4 ).Infof ("Checking if partition path %q exists..." , pathName )
790
846
791
- // F5 iControl REST API expects / characters in the path to be
792
- // escaped as ~.
793
847
uri := fmt .Sprintf ("https://%s/mgmt/tm/sys/folder/%s" ,
794
- f5 .host , strings . Replace (pathName , "/" , "~" , - 1 ))
848
+ f5 .host , encodeiControlUriPathComponent (pathName ))
795
849
796
850
err := f5 .get (uri , nil )
797
851
if err != nil {
@@ -1012,9 +1066,10 @@ func (f5 *f5LTM) CreatePool(poolname string) error {
1012
1066
// From @Miciah: In the future, we should allow the administrator
1013
1067
// to specify a different monitor to use.
1014
1068
payload := f5Pool {
1015
- Mode : "round-robin" ,
1016
- Monitor : "min 1 of /Common/http /Common/https" ,
1017
- Name : poolname ,
1069
+ Mode : "round-robin" ,
1070
+ Monitor : "min 1 of /Common/http /Common/https" ,
1071
+ Partition : f5 .partitionPath ,
1072
+ Name : poolname ,
1018
1073
}
1019
1074
1020
1075
err := f5 .post (url , payload , nil )
@@ -1036,7 +1091,8 @@ func (f5 *f5LTM) CreatePool(poolname string) error {
1036
1091
// DeletePool deletes the specified pool from F5 BIG-IP, and deletes
1037
1092
// f5.poolMembers[poolname].
1038
1093
func (f5 * f5LTM ) DeletePool (poolname string ) error {
1039
- url := fmt .Sprintf ("https://%s/mgmt/tm/ltm/pool/%s" , f5 .host , poolname )
1094
+ url := fmt .Sprintf ("https://%s/mgmt/tm/ltm/pool/%s" , f5 .host ,
1095
+ f5 .iControlUriResourceId (poolname ))
1040
1096
1041
1097
err := f5 .delete (url , nil )
1042
1098
if err != nil {
@@ -1062,7 +1118,7 @@ func (f5 *f5LTM) GetPoolMembers(poolname string) (map[string]bool, error) {
1062
1118
}
1063
1119
1064
1120
url := fmt .Sprintf ("https://%s/mgmt/tm/ltm/pool/%s/members" ,
1065
- f5 .host , poolname )
1121
+ f5 .host , f5 . iControlUriResourceId ( poolname ) )
1066
1122
1067
1123
res := f5PoolMemberset {}
1068
1124
@@ -1125,7 +1181,7 @@ func (f5 *f5LTM) AddPoolMember(poolname, member string) error {
1125
1181
glog .V (4 ).Infof ("Adding pool member %s to pool %s." , member , poolname )
1126
1182
1127
1183
url := fmt .Sprintf ("https://%s/mgmt/tm/ltm/pool/%s/members" ,
1128
- f5 .host , poolname )
1184
+ f5 .host , f5 . iControlUriResourceId ( poolname ) )
1129
1185
1130
1186
payload := f5PoolMember {
1131
1187
Name : member ,
@@ -1164,7 +1220,7 @@ func (f5 *f5LTM) DeletePoolMember(poolname, member string) error {
1164
1220
}
1165
1221
1166
1222
url := fmt .Sprintf ("https://%s/mgmt/tm/ltm/pool/%s/members/%s" ,
1167
- f5 .host , poolname , member )
1223
+ f5 .host , f5 . iControlUriResourceId ( poolname ) , member )
1168
1224
1169
1225
err = f5 .delete (url , nil )
1170
1226
if err != nil {
@@ -1187,7 +1243,7 @@ func (f5 *f5LTM) getRoutes(policyname string) (map[string]bool, error) {
1187
1243
}
1188
1244
1189
1245
url := fmt .Sprintf ("https://%s/mgmt/tm/ltm/policy/%s/rules" ,
1190
- f5 .host , policyname )
1246
+ f5 .host , f5 . iControlUriResourceId ( policyname ) )
1191
1247
1192
1248
res := f5PolicyRuleset {}
1193
1249
@@ -1257,8 +1313,9 @@ func (f5 *f5LTM) addRoute(policyname, routename, poolname, hostname,
1257
1313
pathname string ) error {
1258
1314
success := false
1259
1315
1316
+ policyResourceId := f5 .iControlUriResourceId (policyname )
1260
1317
rulesUrl := fmt .Sprintf ("https://%s/mgmt/tm/ltm/policy/%s/rules" ,
1261
- f5 .host , policyname )
1318
+ f5 .host , policyResourceId )
1262
1319
1263
1320
rulesPayload := f5Rule {
1264
1321
Name : routename ,
@@ -1288,7 +1345,7 @@ func (f5 *f5LTM) addRoute(policyname, routename, poolname, hostname,
1288
1345
}()
1289
1346
1290
1347
conditionUrl := fmt .Sprintf ("https://%s/mgmt/tm/ltm/policy/%s/rules/%s/conditions" ,
1291
- f5 .host , policyname , routename )
1348
+ f5 .host , policyResourceId , routename )
1292
1349
1293
1350
conditionPayload := f5RuleCondition {
1294
1351
Name : "0" ,
@@ -1330,7 +1387,7 @@ func (f5 *f5LTM) addRoute(policyname, routename, poolname, hostname,
1330
1387
}
1331
1388
1332
1389
actionUrl := fmt .Sprintf ("https://%s/mgmt/tm/ltm/policy/%s/rules/%s/actions" ,
1333
- f5 .host , policyname , routename )
1390
+ f5 .host , policyResourceId , routename )
1334
1391
1335
1392
actionPayload := f5RuleAction {
1336
1393
Name : "0" ,
@@ -1523,7 +1580,7 @@ func (f5 *f5LTM) DeletePassthroughRoute(routename string) error {
1523
1580
// policy.
1524
1581
func (f5 * f5LTM ) deleteRoute (policyname , routename string ) error {
1525
1582
ruleUrl := fmt .Sprintf ("https://%s/mgmt/tm/ltm/policy/%s/rules/%s" ,
1526
- f5 .host , policyname , routename )
1583
+ f5 .host , f5 . iControlUriResourceId ( policyname ) , routename )
1527
1584
1528
1585
err := f5 .delete (ruleUrl , nil )
1529
1586
if err != nil {
@@ -1844,7 +1901,7 @@ func (f5 *f5LTM) associateClientSslProfileWithVserver(profilename,
1844
1901
profilename , vservername )
1845
1902
1846
1903
vserverProfileUrl := fmt .Sprintf ("https://%s/mgmt/tm/ltm/virtual/%s/profiles" ,
1847
- f5 .host , vservername )
1904
+ f5 .host , f5 . iControlUriVserverId ( vservername ) )
1848
1905
1849
1906
vserverProfilePayload := f5VserverProfilePayload {
1850
1907
Name : profilename ,
@@ -1862,7 +1919,7 @@ func (f5 *f5LTM) associateServerSslProfileWithVserver(profilename,
1862
1919
profilename , vservername )
1863
1920
1864
1921
vserverProfileUrl := fmt .Sprintf ("https://%s/mgmt/tm/ltm/virtual/%s/profiles" ,
1865
- f5 .host , vservername )
1922
+ f5 .host , f5 . iControlUriVserverId ( vservername ) )
1866
1923
1867
1924
vserverProfilePayload := f5VserverProfilePayload {
1868
1925
Name : profilename ,
@@ -1890,7 +1947,7 @@ func (f5 *f5LTM) deleteCertParts(routename string,
1890
1947
routename , f5 .httpsVserver )
1891
1948
serverSslProfileName := fmt .Sprintf ("%s-server-ssl-profile" , routename )
1892
1949
serverSslVserverProfileUrl := fmt .Sprintf ("https://%s/mgmt/tm/ltm/virtual/%s/profiles/%s" ,
1893
- f5 .host , f5 .httpsVserver , serverSslProfileName )
1950
+ f5 .host , f5 .iControlUriVserverId ( f5 . httpsVserver ) , serverSslProfileName )
1894
1951
err := f5 .delete (serverSslVserverProfileUrl , nil )
1895
1952
if err != nil {
1896
1953
// Iff the profile is not associated with the vserver, we can continue on to
@@ -1925,7 +1982,7 @@ func (f5 *f5LTM) deleteCertParts(routename string,
1925
1982
" from vserver %s..." , routename , f5 .httpsVserver )
1926
1983
clientSslProfileName := fmt .Sprintf ("%s-client-ssl-profile" , routename )
1927
1984
clientSslVserverProfileUrl := fmt .Sprintf ("https://%s/mgmt/tm/ltm/virtual/%s/profiles/%s" ,
1928
- f5 .host , f5 .httpsVserver , clientSslProfileName )
1985
+ f5 .host , f5 .iControlUriVserverId ( f5 . httpsVserver ) , clientSslProfileName )
1929
1986
err := f5 .delete (clientSslVserverProfileUrl , nil )
1930
1987
if err != nil {
1931
1988
// Iff the profile is not associated with the vserver, we can continue on
0 commit comments