Advertisement
Guest User

Untitled

a guest
May 18th, 2016
82
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 19.38 KB | None | 0 0
  1. ## This is an example of executing code when your zenpack gets installed (or removed)
  2. ## This __init__.py file should be located at ZenPacks.namespace.Name/ZenPacks/namespace/Name/__init__.py
  3. ## This code should be carefully added to your zenpack so as not to accidently overwrite key methods (
  4.  
  5.  
  6.  
  7. '''
  8. Here begins the non default code
  9. '''
  10. # Import all the things.
  11. import logging
  12. from Products.ZenModel.ZenPack import ZenPack as ZenPackBase
  13.  
  14. # Set Logger to the ZenPack.CustomLoader logger, you can change the logger name to whatever you like.
  15. # Log information shows up in $ZENHOME/log/events.log, as well as stdout if installing/removing via the command line
  16. log = logging.getLogger('zen.ZenPack.CustomLoader')
  17.  
  18. # Make our configuration variable names global,
  19. # its easier than passing them around to every method
  20. global deviceClassToAdd
  21. global templatesToAdd
  22. global eventClassToAdd
  23. global leaveDeviceClass
  24. global updateTemplates
  25.  
  26.  
  27. '''
  28. Create device class, event class and assign monitoring templates
  29. '''
  30. # If you add a device class to a ZenPack, when you remove the zenpack, it removes the device class
  31. # This may have undesirable / catastrophic results as removing a device class removes all devices and subdevices/classes without warning
  32. # Adding the device class in this way means that we have greater control over the device class and what properties get set and how
  33.  
  34. # We use deviceClassToAdd as a dictionary of classes and templates
  35. # Template name should be identical to the one either already in Zenoss or provided in the objects.xml or zenpacklib.yml file within the ZenPack
  36. # Thats right, you can use this way of adding templates to add classes that are provided by other zenpacks
  37. # Leaving the value as an empty list means that no changes get done, the class just inherits from the parent
  38. # If a parent doesn't exist, it automatically gets created
  39. deviceClassToAdd = {'Server/Linux/Example/AuthenticationServer' : ['AuthenticationServerCore', 'AuthenticationServerUsers'],
  40. 'Server/Linux/Example/Dummy': []
  41. }
  42.  
  43. # Event classes are much less impactful when removing a zenpack, The only problem you might find is when multiple zenpacks/templates
  44. # share a common event class
  45. # As such, I find this approach much easier, this also covers issues where you want to add an event class as a child of another class
  46. # however the parent doesn't exist on the zenoss install you're installing to.
  47. # If a parent doesn't exist, it automatically gets created
  48. eventClassToAdd = ['App/Example/AuthenticationServer',
  49. '/Example/Dummy']
  50.  
  51.  
  52. # These our the properties that mean our classes stick around during an uninstall or not
  53. # Times when you want to keep the classes are when you have other zenpacks that are using the class, or a child of the class
  54. # Or when you want to keep things around for posterity because you're a sentimental old fool and you like a bit of whimsy.
  55. leaveDeviceClass = True
  56. leaveEventClass = True
  57. '''
  58. End Lazy Loader config
  59. '''
  60.  
  61. # This is now the default ZenPack(ZenPackBase) class that you *should* find in your __init__.py file already
  62. # Some parts you may want to remove depending on if you're using zenpacklib or not (you probably do want to be using zenpacklib)
  63. class ZenPack(ZenPackBase):
  64.  
  65. '''
  66. Only defiine zProperties here if you're not using zenpacklib!!
  67. '''
  68. # All zProperties defined here will automatically be created when the
  69. # ZenPack is installed. These properties will be removed when removing the ZenPack.
  70. packZProperties = [
  71. ('zAuthenticationServerJmxPort', 12345, 'int'),
  72. ]
  73.  
  74.  
  75. # This is the standard install method. It gets called when you install the zenpack
  76. def install(self, app):
  77.  
  78. log.info('Beginning Installation.')
  79.  
  80. # Create the new device classes and add templates
  81. # We iterate over the class/templates in the deviceClassToAdd dictionary
  82. for classToAdd, templatesToAdd in deviceClassToAdd.iteritems():
  83. # Add the requested device class
  84. # Here we kick our the actual creation to a new method to make things easier for us
  85. addedDeviceClass = self.createDeviceOrganiserPath(classToAdd)
  86. # You can also run a bunch of custom stuff here on the new addedDeviceClass if you want
  87. # for example you can set the properties using
  88. # addedDeviceClass.zCommandUsername = "root"
  89. # addedDeviceClass.zCommandPassword = "NOTSECURE"
  90. # Obviously, any passwords you put in here aren't secure, as your __init__.py is plain text!
  91.  
  92. # Once the class is added, we can add the template, only if the template list has an element
  93. # Again we kick it out to a new method to make things easier for us
  94. if len(templatesToAdd) > 0:
  95. # Add the requested templates to the new device class
  96. self.setTemplates(addedDeviceClass, templatesToAdd)
  97.  
  98. # Create the event class
  99. # Simple one this, again we kick it out to another new method
  100. for eventClass in eventClassToAdd:
  101. addedEventClass = self.createEventOrganiserPath(eventClass)
  102. # You can also run a bunch of custom stuff here on the new addedEventClass if you want
  103. # for example you can set the transform using
  104. # addedEventClass.transform = "evt.severity = 5"
  105.  
  106.  
  107. # But wait, theres more!
  108. # You can also manipulate code here that's not added as part of your zenpack at all.
  109. # Say you were just adding a template to an existing class, but not the class itself (updated linux monitoring for your environment for example)
  110. # You can adjust properties here as well directly by using the object directly from dmd
  111. # dmd.Devices.Server.Linux.zKeyPath = "/opt/zenoss/SSHKeys/zenoss_key"
  112. # The same goes for event classes using
  113. # dmd.Events.App.Example.transform = "evt.severity = 5"
  114.  
  115.  
  116. # Instruct Zenoss to install any objects into Zope from the objects.xml file contained inside the ZenPack
  117. # Once you get down here, running this next line will tell zenoss to install the zenpack as it normally would
  118. # Double check with your existing __init__.py file if you're using zenpacklib as I believe it does the install
  119. # in a different way
  120. ZenPackBase.install(self, app)
  121.  
  122.  
  123.  
  124.  
  125. # This is the standard remove method
  126. # it gets called when you remove the zenpack
  127. def remove(self, app, leaveObjects=False):
  128.  
  129. log.info('Beginning ZenPack removal.')
  130.  
  131. # Remove the device class, this ensures that we don't remove devices as well if we don't want to
  132. # Again we iterate over the device classes and templates that the zenpack adds
  133. for classToRemove, templatesToRemove in deviceClassToAdd.iteritems():
  134. if self.dmd.Devices.getOrganizer(classToRemove):
  135. # Only if we're removing templates do we run the new method to remove templates from device classes
  136. if len(templatesToRemove) > 0:
  137. self.removeTemplatesFromDeviceClass(classToRemove, templatesToRemove)
  138. # This check here is what stops us removing device classes. If we have leaveDeviceClass set to True,
  139. # then the device class will be left behind
  140. if leaveDeviceClass == False:
  141. deviceList = self.removeDeviceOrganiser(classToRemove)
  142.  
  143. # Same thing for the event class
  144. if leaveEventClass == False:
  145. # Iterate over the event classes that we added and remove them
  146. for eventClass in eventClassToAdd:
  147. if self.dmd.Events.getOrganizer(eventClassToAdd):
  148. self.removeEventOrganiser(eventClassToAdd)
  149.  
  150.  
  151. # But wait, theres more!
  152. # If you made any custom changes to the install method, you might want to revert them in the remove method as well!
  153. # Or you might not! You can choose!
  154. # You can also manipulate code here that's not added as part of your zenpack at all.
  155. # Say you were just adding a template to an existing class, but not the class itself (updated linux monitoring for your environment for example)
  156. # You can adjust properties here as well directly by using the object directly from dmd
  157. # dmd.Devices.Server.Linux.zKeyPath = "/opt/zenoss/SSHKeys/zenoss_key"
  158. # The same goes for event classes using
  159. # dmd.Events.App.Example.transform = "evt.severity = 5"
  160.  
  161.  
  162.  
  163. # Instruct Zenoss to remove any objects from Zope from the objects.xml file contained inside the ZenPack
  164. # Once you get down here, running this next line will tell zenoss to remove the zenpack as it normally would
  165. # Double check with your existing __init__.py file if you're using zenpacklib as I believe it does the remove
  166. # in a different way
  167. ZenPackBase.remove(self, app)
  168.  
  169.  
  170. '''The Installation Methods'''
  171. # All the new custom methods that will install things for you
  172.  
  173.  
  174. def createDeviceOrganiserPath(self, deviceClassToAddString):
  175. '''
  176. This creates the iterative device class path
  177. Why do we do it this way? Well if you want to add /Server/Linux/Foo/Bar in your zenpack
  178. but /Server/Linux/Foo doesn't exist in your zenoss install then you get a slightly confusing
  179. KeyError exception when you try and install things
  180. Adding the device class iteratively gets around this
  181. '''
  182.  
  183. # Split up the requested device class and sequentially create it.
  184. classList = []
  185. classList = deviceClassToAddString.split('/')
  186.  
  187. # Loop over the Class List and create all required child classes.
  188. for i in range(len(classList)):
  189. org = ('/').join(classList[:len(classList)+1-(len(classList)-i)]) # The sequenial path generator! Fear it's confusion.
  190. try:
  191. # Test for the class already existing
  192. if self.dmd.Devices.getOrganizer(org):
  193. log.info('Device Class %s already exists.', str(org))
  194. except KeyError:
  195. # The class doesn't exist, so we create it.
  196. log.info('Creating new device class at %s', str(org))
  197. self.dmd.Devices.createOrganizer(org)
  198. from transaction import commit
  199. commit()
  200.  
  201. return self.dmd.Devices.getOrganizer(deviceClassToAddString)
  202.  
  203. def setTemplates(self, deviceClass, newTemplates):
  204. '''
  205. This new method sets the templates for us. We do this by
  206. manipulating the zDeviceTemplates property of the class
  207. '''
  208.  
  209. # Obtain the zDeviceTemplates of the newly created class, and add any extras.
  210. # We don't need to worry about getting the parent templates and artificially inheriting them,
  211. # Zenoss takes care of this for us.
  212. log.info('The following templates will be added; %s.', str(newTemplates))
  213.  
  214. # Get the zDeviceTemplates of the new device class and copy it to a new list
  215. templates = list(deviceClass.zDeviceTemplates)
  216. log.info('The following templates have been inherited already; %s', str(templates))
  217.  
  218. # Loop over the list of templates provided in the config section
  219. updateTemplates = False
  220. for template in newTemplates:
  221. if template not in templates:
  222. # Template is new, so we add it to the templates list.
  223. templates.append(template)
  224. updateTemplates = True
  225. log.info('%s added to templates', template)
  226.  
  227. if updateTemplates == True:
  228. # If we need to update the templates on the device class, here we set the Zen Property and commit the change
  229. # Doing this automatically sets the zDeviceTemplates as a local copy
  230. # It will stop inheriting changes to parent properties!
  231. deviceClass.setZenProperty( 'zDeviceTemplates', templates )
  232. log.info('Device Class zDeviceTemplates updated to: %s', str(templates))
  233. from transaction import commit
  234. commit()
  235. else:
  236. # We don't have to update the templates, so we just log that and end the function
  237. # This way we don't start creating local copies of the zproperty if you dont need to
  238. log.info('No new templates need to be added.')
  239.  
  240. def createEventOrganiserPath(self, eventClass):
  241. '''
  242. This is very similar to the deviceClass method above, but this only only creates
  243. event classes.
  244. '''
  245. # Split up the requested event class and sequentially create it.
  246. classList = []
  247. classList = eventClass.split('/')
  248.  
  249. # Loop over the Event list and create all required child classes.
  250. for i in range(len(classList)):
  251. org = ('/').join(classList[:len(classList)+1-(len(classList)-i)]) # The sequenial path generator! Fear it's confusion.
  252. try:
  253. # Test if the event class already exists
  254. if self.dmd.Events.getOrganizer(org):
  255. log.info('Event Class %s already exists.', str(org))
  256. except KeyError:
  257. # The class doesn't exist, so we create it
  258. log.info('Creating new event class at %s', str(org))
  259. self.dmd.Events.createOrganizer(org)
  260. from transaction import commit
  261. commit()
  262.  
  263. return self.dmd.Events.getOrganizer(eventClass)
  264.  
  265.  
  266.  
  267. '''The Removal Methods'''
  268.  
  269. def removeTemplatesFromDeviceClass(self, deviceClassToRemoveString, templatesToRemove):
  270. '''
  271. This new method removes the previously added templates for us. We do this by
  272. manipulating the zDeviceTemplates property of the class
  273. '''
  274. # Obtain the device class that we need to remeove the tempalte from
  275. deviceClass = self.dmd.Devices.getOrganizer(deviceClassToRemoveString)
  276. # Copy the device template list from the device class
  277. templates = list(deviceClass.zDeviceTemplates)
  278.  
  279. # Loop over the list of templates that we need to remove from the device class
  280. updateTemplates = False
  281. for template in templatesToRemove:
  282. if template in templates:
  283. # The template to remove has been found in the current templates. We remove it from the list
  284. templates.remove(template)
  285. log.info('%s has been configured to be removed from the Device Class %s' % (template, deviceClassToRemoveString))
  286. updateTemplates = True
  287. else:
  288. # The template hasn't been found. We don't need to remove the template.
  289. log.info("%s hasn't been found within the existing list of templates: %s" % (template, templates))
  290.  
  291. if updateTemplates == True:
  292. # Taking our new templates list, we set the Device class property as required and commit
  293. # It should be noted that this will still leave the zProperty as a local copy
  294. # its left as an exercise for the reader to determine if they want this behaviour,
  295. # and if not, adjust the code accordingly.
  296. deviceClass.setZenProperty( 'zDeviceTemplates', templates )
  297. log.info('Device Class zDeviceTemplates updated to: %s', str(templates))
  298. from transaction import commit
  299. commit()
  300. else:
  301. # Nothing to be done. Log and end the function.
  302. log.info('No templates need to be removed')
  303.  
  304.  
  305. def removeDeviceOrganiser(self, deviceClassToRemoveString):
  306. '''
  307. If you want to remove the device class then this chap will run
  308. The benefit of using this code is that while the deviceClass gets removed
  309. the devices in it will be moved to a new Homeless class so that the don't get
  310. completely deleted. You can then delete them manually at your own discretion
  311. '''
  312.  
  313. # Get our created child device class
  314. deviceClassToRemove = self.dmd.Devices.getOrganizer(deviceClassToRemoveString)
  315.  
  316. log.info('The following device class will be removed: %s', str(deviceClassToRemove))
  317.  
  318. # Check if the device class is empty of devices, if its not remidiate.
  319. if len(deviceClassToRemove.getSubDevices_recursive()) > 0:
  320. log.warn('Devices exist within this device class. They will be moved to a holding area under the existing OS class.')
  321.  
  322. # Set the parent OS device Class, either a two stage Class is returned (Server/Linux), or a one stage class (Networking)
  323. try:
  324. parentOSClass = ('/').join(deviceClassToRemoveString.split('/')[:2])
  325. except:
  326. parentOSClass = ('/').join(deviceClassToRemoveString.split('/')[:1])
  327.  
  328. # Create a homeless class string based on the parent class
  329. homelessClass = parentOSClass + '/' + 'Homeless'
  330.  
  331. try:
  332. # Try and get the homeless class object
  333. if self.dmd.Devices.getOrganizer(homelessClass):
  334. log.info('Device Class %s already exists.', str(homelessClass))
  335. except KeyError:
  336. # The homeless class doesn't exist, so we create it
  337. log.info('Creating new Device Class at %s', str(homelessClass))
  338. self.dmd.Devices.createOrganizer(homelessClass)
  339.  
  340. for dev in deviceClassToRemove.devices():
  341. # Move the devices in our target device class to the homeless device class
  342. log.info('Moving device %s to the Homeless Device Class.', dev.id)
  343. dev.changeDeviceClass(homelessClass)
  344.  
  345. # Test again to see if there are devices in the class. If there are, something very wrong has broken and we log an error
  346. if len(deviceClassToRemove.getSubDevices_recursive()) > 0:
  347. log.error('Devices exist within this Device Class. Even after moving them to a new class. Something very wrong has happened. The Device Class will NOT be removed.')
  348. else:
  349. # Everything has worked correctly, we remove our target device class
  350. log.info('Attempting to remove the device class.')
  351. classParent = deviceClassToRemove.getParentNode()
  352. classParent.manage_deleteOrganizer(deviceClassToRemoveString.split('/')[-1])
  353.  
  354. else:
  355. # No devices exist within our target device class, we can just remove the class
  356. classParent = deviceClassToRemove.getParentNode()
  357. classParent.manage_deleteOrganizer(deviceClassToRemoveString.split('/')[-1])
  358.  
  359.  
  360. def removeEventOrganiser(self, eventClassToRemoveString):
  361. '''
  362. Removing the event class is much easier, we don't need to worry about devices or events
  363. being contained within the event class here.
  364. '''
  365. log.info('Removing the Event Class %s', eventClassToRemoveString)
  366.  
  367. # Get our created child event class
  368. eventClassToRemove = self.dmd.Events.getOrganizer(eventClassToRemoveString)
  369. # Get our event class parent
  370. classParent = eventClassToRemove.getParentNode()
  371. # And remove the Event Class in question from its parent.
  372. classParent.manage_deleteOrganizer(eventClassToRemoveString.split('/')[-1])
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement