1414#
1515#
1616
17+ from f5 .bigip .mixins import DeviceMixin
1718from f5 .common import pollster
19+ from f5 .managers .device_group_manager import DeviceGroupManager
1820
1921
2022class BigIPDeviceNotInExpectedState (Exception ):
@@ -29,124 +31,169 @@ class UnexpectedBigIPState(Exception):
2931 pass
3032
3133
32- class ClusterManager (object ):
34+ class ClusterManager (DeviceMixin ):
3335 '''Manage a cluster of BigIPs.
3436
3537 This is accomplished with REST URI calls only, but some operations are
36- only permitted through the CLI (such as adding peers via cm/trust-domain).
38+ only permitted via tmsh commands (such as adding cm/trust-domain peers ).
3739 We get around this issue by deploying iApps (sys/application).
3840 '''
3941
4042 iapp_actions = {'definition' : {'implementation' : None , 'presentation' : '' }}
4143 sync_status_entry = 'https://localhost/mgmt/tm/cm/sync-status/0'
4244
4345 def __init__ (self , bigips , cluster_name , partition , cluster_type ):
44- if len (bigips ) > 4 :
46+ if len (bigips ) > 8 :
4547 raise ClusterNotSupported (
4648 'The number of devices to cluster is not supported.'
4749 )
4850 self .bigips = bigips
49- self .bigip_trust_root = self .bigips [0 ]
51+ self .root_bigip = self .bigips [0 ]
5052 self .peers = self .bigips [1 :]
5153 self .cluster_name = cluster_name
52- self .device_iapp_name = 'device_iapp'
53- self .cluster_iapp_name = 'cluster_iapp'
54+ self .peer_iapp_prefix = 'cluster_iapp'
5455 self .partition = partition
5556 self .cluster_type = cluster_type
57+ self .device_group = DeviceGroupManager (
58+ cluster_name , self .root_bigip , partition
59+ )
5660
57- def cluster_bigips (self ):
58- if len (self ._get_bigips_by_activation_state ('active' )) != \
59- len (self .bigips ):
60- raise BigIPDeviceNotInExpectedState (
61- 'One or more BigIP devices was not in a active/licensed state.'
62- )
63- print ('Adding trusted peers...' )
64- self ._add_peers ()
61+ def create_bigip_cluster (self ):
62+ '''Cluster the BigIP devices given.'''
63+ self ._ensure_bigips_active_licensed ()
6564 print ('Creating cluster group...' )
66- self ._create_cluster_group ()
65+ self ._create_device_cluster ()
6766 if self .cluster_type == 'sync-failover' :
6867 print ('Ensure cluster has settled into active/standby...' )
69- self ._ensure_active_standby ()
68+ self ._devices_in_standby ()
7069 elif self .cluster_type == 'sync-only' :
7170 print ('Ensure devices are all in sync and active...' )
72- self .bigip_trust_root .cm .sync (self .cluster_name )
71+ self .root_bigip .cm .sync (self .cluster_name )
7372 self ._all_devices_in_sync ()
7473
75- def _add_peers (self ):
76- peer_cmds = []
74+ def teardown_bigip_cluster (self ):
75+ '''Teardown cluster of BigIP devices.'''
76+
77+ if self .cluster_type == 'sync-failover' :
78+ self ._devices_in_standby ()
79+ self .root_bigip .cm .sync (self .cluster_name )
80+ self .device_group .teardown_device_group (self .bigips )
81+ # remove other devices from each device
7782 for peer in self .peers :
78- peer_cmds .append (self ._get_add_peer_command (peer ))
79- iapp_actions = self .iapp_actions .copy ()
80- iapp_actions ['definition' ]['implementation' ] = '\n ' .join (peer_cmds )
81- self ._deploy_iapp (self .cluster_iapp_name , iapp_actions )
82-
83- def _create_cluster_group (self ):
84- self .bigip_trust_root .cm .device_groups .device_group .create (
85- name = self .cluster_name ,
86- partition = self .partition ,
87- type = self .cluster_type
83+ self ._modify_trusted_peer (
84+ peer , self ._get_delete_peer_command , peer
85+ )
86+
87+ def _ensure_bigips_active_licensed (self ):
88+ '''All devices should be in an active/licensed state.'''
89+ if len (self ._get_bigips_by_activation_state ('active' )) != \
90+ len (self .bigips ):
91+ raise BigIPDeviceNotInExpectedState (
92+ 'One or more BigIP devices was not in a active/licensed state.'
93+ )
94+
95+ def scale_cluster_up (self , bigip ):
96+ '''Scale cluster up by one device.
97+
98+ :param bigip: bigip object -- bigip to add
99+ '''
100+
101+ if len (self .bigips ) == 8 :
102+ raise ClusterNotSupported (
103+ 'The number of devices to cluster is not supported.'
104+ )
105+ self ._modify_trusted_peer (
106+ bigip , self ._get_add_peer_command , self .root_bigip
88107 )
89- for bigip in self .bigips :
90- self ._add_device_to_device_group (bigip )
108+ self .device_group .scale_up_device_group (bigip )
109+ self .bigips .append (bigip )
110+
111+ def scale_cluster_down (self , bigip ):
112+ '''Scale cluster down by one device.
113+
114+ :param bigip: bigip object -- bigip to delete
115+ '''
91116
92- def _ensure_active_standby (self ):
93- self ._devices_in_standby ()
117+ self .device_group .scale_down_device_group (bigip )
118+ self ._modify_trusted_peer (
119+ bigip , self ._get_delete_peer_command , self .root_bigip
120+ )
121+ self .bigips .remove (bigip )
122+
123+ def _create_device_cluster (self ):
124+ '''Deploy an iapp to add trusted peers, then create device group.'''
125+
126+ for peer in self .peers :
127+ self ._modify_trusted_peer (
128+ peer , self ._get_add_peer_command , self .root_bigip
129+ )
130+ self ._all_devices_in_sync ()
131+ self .device_group .create_device_group (self .bigips , self .cluster_type )
132+
133+ def _modify_trusted_peer (
134+ self , peer , mod_peer_func , deploy_bigip
135+ ):
136+ '''Modify a trusted peer device.
137+
138+ :param peer: bigip object -- peer to modify
139+ :param mod_peer_func: function -- function to call to modify peer
140+ '''
141+
142+ peer_info = self ._get_device_info (peer )
143+ iapp_name = '%s_%s' % (self .peer_iapp_prefix , peer_info .name )
144+ mod_peer_cmd = mod_peer_func (peer )
145+ iapp_actions = self .iapp_actions .copy ()
146+ iapp_actions ['definition' ]['implementation' ] = mod_peer_cmd
147+ self ._deploy_iapp (iapp_name , iapp_actions , deploy_bigip )
148+ # Once the command has been run via the iapp, delete the iapp
149+ self ._delete_iapp (iapp_name , deploy_bigip )
94150
95151 @pollster .poll_by_method
96152 def _all_devices_in_sync (self ):
153+ '''Wait until all devices have failover status of 'In Sync'.'''
97154 assert len (self ._get_bigips_by_failover_status ('In Sync' )) == \
98155 len (self .bigips )
99156
100157 @pollster .poll_by_method
101158 def _devices_in_standby (self ):
159+ '''Wait until n-1 devices in 'standby' activation state.'''
102160 standby_bigips = \
103161 self ._get_bigips_by_activation_state ('standby' )
104162 assert len (standby_bigips ) == (len (self .bigips )- 1 )
105163 return standby_bigips
106164
107165 def _get_bigips_by_failover_status (self , status ):
166+ '''Get a list of bigips by failover status.'''
108167 bigips = []
109168 for bigip in self .bigips :
110169 sync_status = bigip .cm .sync_status
111170 sync_status .refresh ()
112171 current_status = (sync_status .entries [self .sync_status_entry ]
113172 ['nestedStats' ]['entries' ]['status' ]
114173 ['description' ])
115- print (current_status )
116174 if status == current_status :
117175 bigips .append (bigip )
118176 return bigips
119177
120178 def _get_bigips_by_activation_state (self , state ):
179+ '''Get a list of bigips by activation statue.'''
121180 bigips = []
122181 for bigip in self .bigips :
123- reg = bigip .shared .licensing .registration .load ()
124182 act = bigip .cm .devices .device .load (
125183 name = self ._get_device_info (bigip ).name ,
126184 partition = self .partition
127185 )
128- if reg . licensedVersion != '' and act .failoverState == state :
186+ if act .failoverState == state :
129187 bigips .append (bigip )
130188 return bigips
131189
132- def teardown_cluster (self ):
133- self ._remove_iapp (self .cluster_iapp_name )
134- if self .cluster_type == 'sync-failover' :
135- self ._devices_in_standby ()
136- self .bigip_trust_root .cm .sync (self .cluster_name )
137- dg = self .bigip_trust_root .cm .device_groups .device_group .load (
138- name = self .cluster_name , partition = self .partition
139- )
140- for bigip in self .bigips :
141- bigip_info = self ._get_device_info (bigip )
142- dgd = dg .devices_s .devices .load (
143- name = bigip_info .name , partition = self .partition
144- )
145- dgd .delete ()
146- dg .delete ()
190+ def _delete_iapp (self , iapp_name , deploy_bigip ):
191+ '''Delete an iapp service and template on the root device.
192+
193+ :param iapp_name: str -- name of iapp
194+ '''
147195
148- def _remove_iapp (self , iapp_name ):
149- iapp = self .bigip_trust_root .sys .applications
196+ iapp = deploy_bigip .sys .applications
150197 iapp_service = iapp .services .service .load (
151198 name = iapp_name , partition = self .partition
152199 )
@@ -156,43 +203,42 @@ def _remove_iapp(self, iapp_name):
156203 )
157204 iapp_template .delete ()
158205
159- def _get_device_info (self , bigip ):
160- coll = bigip .cm .devices .get_collection ()
161- device = [device for device in coll if device .selfDevice == 'true' ]
162- assert len (device ) == 1
163- return device [0 ]
206+ def _deploy_iapp (self , iapp_name , actions , deploy_bigip ):
207+ '''Deploy iapp on the root device.
164208
165- def _add_device_to_device_group (self , bigip ):
166- bigip_info = self ._get_device_info (bigip )
167- poll_for_dg = pollster .poll_by_method (
168- bigip .cm .device_groups .device_group .load
169- )
170- dg = poll_for_dg (
171- name = self .cluster_name , partition = self .partition
172- )
173- dg .devices_s .devices .create (
174- name = bigip_info .name , partition = self .partition
175- )
176- root_dg = self .bigip_trust_root .cm .device_groups .device_group .load (
177- name = self .cluster_name , partition = self .partition
178- )
179- trust_root_poll = pollster .poll_by_method (
180- root_dg .devices_s .devices .load
181- )
182- trust_root_poll (name = bigip_info .name , partition = self .partition )
209+ :param iapp_name: str -- name of iapp
210+ :param actions: dict -- actions definition of iapp sections
211+ '''
183212
184- def _deploy_iapp (self , iapp_name , actions ):
185- tmpl = self .bigip_trust_root .sys .applications .templates .template
186- serv = self .bigip_trust_root .sys .applications .services .service
213+ tmpl = deploy_bigip .sys .applications .templates .template
214+ serv = deploy_bigip .sys .applications .services .service
187215 tmpl .create (name = iapp_name , partition = self .partition , actions = actions )
188216 serv .create (
189217 name = iapp_name , partition = self .partition , template = iapp_name
190218 )
191219
192220 def _get_add_peer_command (self , peer ):
221+ '''Get tmsh command to add a trusted peer.
222+
223+ :param peer: bigip object -- peer device
224+ :returns: str -- tmsh command to add trusted peer
225+ '''
226+
193227 peer_device = self ._get_device_info (peer )
194228 add_peer_cmd = 'tmsh::modify cm trust-domain Root ca-devices add ' \
195229 '\\ {{ {0} \\ }} name {1} username admin password admin' .format (
196230 peer_device .managementIp , peer_device .name
197231 )
198232 return add_peer_cmd
233+
234+ def _get_delete_peer_command (self , peer ):
235+ '''Get tmsh command to delete a trusted peer.
236+
237+ :param peer: bigip object -- peer device
238+ :returns: str -- tmsh command to delete trusted peer
239+ '''
240+
241+ peer_device = self ._get_device_info (peer )
242+ del_peer_cmd = 'tmsh::modify cm trust-domain Root ca-devices delete ' \
243+ '\\ { %s \\ }' % peer_device .name
244+ return del_peer_cmd
0 commit comments