├── .gitignore ├── COPYRIGHT.txt ├── LICENSE.txt ├── MANIFEST.in ├── README.markdown ├── README.mediawiki ├── ZenPacks ├── __init__.py └── zenoss │ ├── CloudStack │ ├── Cloud.py │ ├── Cluster.py │ ├── Host.py │ ├── Pod.py │ ├── RouterVM.py │ ├── SystemVM.py │ ├── VirtualMachine.py │ ├── Zone.py │ ├── __init__.py │ ├── browser │ │ ├── __init__.py │ │ ├── configure.zcml │ │ └── resources │ │ │ ├── img │ │ │ └── cloudstack.png │ │ │ └── js │ │ │ ├── cloud.js │ │ │ └── cloudstack.js │ ├── configure.zcml │ ├── deviceloaders.py │ ├── dynamicview │ │ ├── __init__.py │ │ ├── adapters.py │ │ └── configure.zcml │ ├── facades.py │ ├── impact.py │ ├── info.py │ ├── interfaces.py │ ├── lib │ │ ├── __init__.py │ │ └── txcloudstack.py │ ├── locallibs.py │ ├── migrate │ │ ├── MigratePassword.py │ │ └── __init__.py │ ├── modeler │ │ ├── __init__.py │ │ └── plugins │ │ │ ├── __init__.py │ │ │ └── zenoss │ │ │ ├── CloudStack.py │ │ │ └── __init__.py │ ├── objects │ │ └── objects.xml │ ├── parsers │ │ ├── CloudStack.py │ │ └── __init__.py │ ├── poll_cloudstack.py │ ├── routers.py │ ├── tests │ │ ├── __init__.py │ │ ├── data │ │ │ ├── cloudstack_results.pickle │ │ │ ├── cloudstack_results_missingHosts.pickle │ │ │ ├── cloudstack_results_noZones.pickle │ │ │ ├── listalertsresponse.json │ │ │ ├── listcapacityresponse.json │ │ │ ├── listclustersresponse.json │ │ │ ├── listconfigurationsresponse.json │ │ │ ├── listeventsresponse.json │ │ │ ├── listhostsresponse.json │ │ │ ├── listpodsresponse.json │ │ │ ├── listroutersresponse.json │ │ │ ├── listsystemvmsresponse.json │ │ │ ├── listvirtualmachinesresponse.json │ │ │ └── listzonesresponse.json │ │ ├── testAPI.py │ │ ├── testModel.py │ │ ├── testObjects.py │ │ ├── testTXCloudStack.py │ │ ├── test_impact.py │ │ └── utils.py │ └── utils.py │ └── __init__.py ├── impact.png ├── impact.yuml ├── screenshots ├── cloudstack_add.png ├── cloudstack_clusters.png ├── cloudstack_events.png ├── cloudstack_graphs1.png ├── cloudstack_graphs2.png ├── cloudstack_graphs3.png ├── cloudstack_hosts.png ├── cloudstack_pods.png └── cloudstack_zones.png └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | dist 3 | *.egg-info 4 | *.pyc 5 | -------------------------------------------------------------------------------- /COPYRIGHT.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2011,2012, Zenoss, Inc. 2 | # 3 | # This program is free software; you can redistribute it and/or modify it 4 | # under the terms of the GNU General Public License version 2 or (at your 5 | # option) any later version as published by the Free Software Foundation. 6 | # 7 | # This program is distributed in the hope that it will be useful, 8 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 | # GNU General Public License for more details. 11 | # 12 | # You should have received a copy of the GNU General Public License 13 | # along with this program; if not, write to the Free Software 14 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 15 | # USA. 16 | # 17 | # For complete information please visit: http://www.zenoss.com/oss/ 18 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | 341 | 342 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | graft ZenPacks 2 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | Documentation can be found [on the Zenoss wiki](http://wiki.zenoss.org/ZenPack:CloudStack). 2 | -------------------------------------------------------------------------------- /README.mediawiki: -------------------------------------------------------------------------------- 1 | Monitoring for [http://incubator.apache.org/cloudstack/ Apache CloudStack] and by extension, [http://www.citrix.com/products/cloudplatform/overview.html Citrix CloudPlatform]. 2 | 3 | The easiest way to start monitoring CloudStack is to navigate to the Infrastructure page, click the *+* menu to add a device and choose ''Add CloudStack''. Fill out the ''URL'', ''API Key'', and ''Secret Key'' fields then click ''OK''. The URL should only include the protocol, host and port (i.e. ''http://cloudstack.example.com/''). You can find or create the keys by logging into the CloudStack web interface and navigate to Accounts and users. 4 | 5 | Zenoss will then add the CloudStack device to the system. For root administrator users, the associated zones, pods, clusters, hosts, system VMs, routers and VMs will also be added; zones, routers and VMs for domain admonistrator users; zones and VMs for all non admonistrator users. Monitoring will also start after the discovery is complete. 6 | 7 | {{#widget:YouTube|id=3hr2H9iMz_o|width=600}} 8 | 9 | == Upgrade Notes == 10 | 11 | If you are upgrading from a version earlier than 1.1.3 you will need to perform the following manual steps after upgrading to fix the collection of network throughput metrics. These steps must be performed on any Zenoss collector server monitoring CloudStack. These steps will remove all historical performance data collected for network throughput, but that matters less because the historical data is completely wrong. If you do not perform these steps, the network data collected after upgrading will continue to be wrong. 12 | 13 | {{note}} These steps are only necessary on Zenoss versions earlier than 5.0. 14 | 15 | 16 | su - zenoss 17 | cd $ZENHOME/perf/Devices 18 | find . -name cloudstack_network\*.rrd -delete 19 | 20 | 21 | == Metrics == 22 | 23 | Once you've successfully added a CloudStack cloud to Zenoss you will begin to see the following metrics available for the entire cloud to root administrator users. These numbers are aggregated from all zones, pods, clusters and hosts. 24 | 25 | * Public IPs: Total and Used 26 | * Private IPs: Total and Used 27 | * Memory: Total (with and without over-provisioning), Allocated and Used 28 | * CPU: Total (with and without over-provisioning), Allocated and Used 29 | * Primary Storage: Total (with and without over-provisioning), Allocated and Used 30 | * Secondary Storage: Total and Used 31 | * Network: Read and Write 32 | 33 | 34 | The same list of metrics is available for each zone to root administrator users. The same metrics with the exception of public IPs and secondary storage are also available for each pod. 35 | 36 | The following metrics are available aggregated to each cluster, and for each host. 37 | 38 | * Memory: Total and Used 39 | * CPU: Total (with and without over-provisioning), Allocated, Used and Cores 40 | * Network: Read and Write 41 | 42 | The following list of metrics is available to non root administrator users. 43 | 44 | * CPU: Cores, Total, Used and Used Percent 45 | * Network: Read and Write 46 | 47 | 48 | == Events == 49 | 50 | CloudStack has both alerts and events. Once you've successfully added a CloudStack cloud to Zenoss you will automatically receive all CloudStack alerts as events in Zenoss. You will also automatically receive all CloudStack events. However, the events will go straight into your event history by default. 51 | 52 | To avoid overloading CloudStack and Zenoss, only the last two (2) days of events will be checked. This allows for timezone discrepancy between the Zenoss and CloudStack servers as well as some downtime without missing events. There is no real-time event collection mechanism with the CloudStack API, so alerts and events will only be polled once per minute. 53 | 54 | == Installed Items == 55 | 56 | Installing the ZenPack will add the following items to your Zenoss system. 57 | 58 | ;Device Classes 59 | * /CloudStack 60 | 61 | ;Configuration Properties 62 | * zCloudStackURL 63 | * zCloudStackAPIKey 64 | * zCloudStackSecretKey 65 | 66 | ;Modeler Plugins 67 | * zenoss.CloudStack 68 | 69 | ;Monitoring Templates 70 | * Cloud 71 | * Zone 72 | * Pod 73 | * Cluster 74 | * Host 75 | * VirtualMachine 76 | 77 | ;Event Classes 78 | * /Status/CloudStack 79 | * /Perf/CloudStack 80 | * /App/CloudStack 81 | 82 | == Changes == 83 | 84 | ;1.2.0 85 | * Hide API secret key (ZEN-21404) 86 | * Migration script (ZEN-21675) 87 | * Allow CloudStack devices to be created for domain administrator users, non-administrator users, in addition to root administrator users. 88 | 89 | ;1.1.3 90 | * Fix monitoring of network throughput metrics. (ZEN-16956) 91 | 92 | ;1.1.2 93 | * Fix conflict with SolarisMonitor 2.2.0. 94 | -------------------------------------------------------------------------------- /ZenPacks/__init__.py: -------------------------------------------------------------------------------- 1 | __import__('pkg_resources').declare_namespace(__name__) 2 | -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/Cloud.py: -------------------------------------------------------------------------------- 1 | ########################################################################### 2 | # 3 | # This program is part of Zenoss Core, an open source monitoring platform. 4 | # Copyright (C) 2011, Zenoss Inc. 5 | # 6 | # This program is free software; you can redistribute it and/or modify it 7 | # under the terms of the GNU General Public License version 2 or (at your 8 | # option) any later version as published by the Free Software Foundation. 9 | # 10 | # For complete information please visit: http://www.zenoss.com/oss/ 11 | # 12 | ########################################################################### 13 | 14 | from Products.ZenModel.Device import Device 15 | from Products.ZenRelations.RelSchema import ToManyCont, ToOne 16 | 17 | 18 | LOCAL_RELNAMES = { 19 | 'zones', 20 | } 21 | 22 | # Guard against conflicting relationships being introduced. (ZEN-12144) 23 | BASE_RELATIONS = tuple( 24 | x for x in Device._relations if x[0] not in LOCAL_RELNAMES) 25 | 26 | 27 | class Cloud(Device): 28 | meta_type = portal_type = "CloudStackCloud" 29 | 30 | _relations = BASE_RELATIONS + ( 31 | ('zones', ToManyCont(ToOne, 32 | 'ZenPacks.zenoss.CloudStack.Zone.Zone', 33 | 'cloud') 34 | ), 35 | ) 36 | 37 | 38 | def isRootAdmin(self): 39 | # only root admin has Pod component 40 | pods = self.getDeviceComponents(type='CloudStackPod') 41 | return len(pods) > 0 42 | 43 | 44 | def getRRDTemplates(self): 45 | templates = super(Cloud, self).getRRDTemplates() 46 | if not self.isRootAdmin(): 47 | return [] 48 | 49 | return templates 50 | -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/Cluster.py: -------------------------------------------------------------------------------- 1 | ########################################################################### 2 | # 3 | # This program is part of Zenoss Core, an open source monitoring platform. 4 | # Copyright (C) 2011, Zenoss Inc. 5 | # 6 | # This program is free software; you can redistribute it and/or modify it 7 | # under the terms of the GNU General Public License version 2 or (at your 8 | # option) any later version as published by the Free Software Foundation. 9 | # 10 | # For complete information please visit: http://www.zenoss.com/oss/ 11 | # 12 | ########################################################################### 13 | 14 | from Products.ZenRelations.RelSchema import ToManyCont, ToOne 15 | 16 | from ZenPacks.zenoss.CloudStack import BaseComponent 17 | 18 | 19 | class Cluster(BaseComponent): 20 | meta_type = portal_type = "CloudStackCluster" 21 | 22 | cluster_type = None 23 | hypervisor_type = None 24 | managed_state = None 25 | 26 | _properties = BaseComponent._properties + ( 27 | {'id': 'cluster_type', 'type': 'string', 'mode': ''}, 28 | {'id': 'hypervisor_type', 'type': 'string', 'mode': ''}, 29 | {'id': 'managed_state', 'type': 'string', 'mode': ''}, 30 | ) 31 | 32 | _relations = BaseComponent._relations + ( 33 | ('pod', ToOne(ToManyCont, 34 | 'ZenPacks.zenoss.CloudStack.Pod.Pod', 35 | 'clusters') 36 | ), 37 | 38 | ('hosts', ToManyCont(ToOne, 39 | 'ZenPacks.zenoss.CloudStack.Host.Host', 40 | 'cluster') 41 | ), 42 | ) 43 | 44 | def device(self): 45 | return self.pod().device() 46 | -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/Host.py: -------------------------------------------------------------------------------- 1 | ########################################################################### 2 | # 3 | # This program is part of Zenoss Core, an open source monitoring platform. 4 | # Copyright (C) 2011, 2013, Zenoss Inc. 5 | # 6 | # This program is free software; you can redistribute it and/or modify it 7 | # under the terms of the GNU General Public License version 2 or (at your 8 | # option) any later version as published by the Free Software Foundation. 9 | # 10 | # For complete information please visit: http://www.zenoss.com/oss/ 11 | # 12 | ########################################################################### 13 | 14 | from Products.ZenRelations.RelSchema import ToMany, ToManyCont, ToOne 15 | 16 | from ZenPacks.zenoss.CloudStack import BaseComponent 17 | from ZenPacks.zenoss.CloudStack.utils import require_zenpack 18 | 19 | 20 | class Host(BaseComponent): 21 | meta_type = portal_type = "CloudStackHost" 22 | 23 | host_type = None 24 | host_state = None 25 | host_events = None 26 | host_version = None 27 | hypervisor = None 28 | capabilities = None 29 | created = None 30 | host_tags = None 31 | ip_address = None 32 | local_storage_active = None 33 | management_server_id = None 34 | 35 | _properties = BaseComponent._properties + ( 36 | {'id': 'host_type', 'type': 'string', 'mode': ''}, 37 | {'id': 'host_state', 'type': 'string', 'mode': ''}, 38 | {'id': 'host_events', 'type': 'string', 'mode': ''}, 39 | {'id': 'host_version', 'type': 'string', 'mode': ''}, 40 | {'id': 'hypervisor', 'type': 'string', 'mode': ''}, 41 | {'id': 'capabilities', 'type': 'string', 'mode': ''}, 42 | {'id': 'created', 'type': 'string', 'mode': ''}, 43 | {'id': 'host_tags', 'type': 'string', 'mode': ''}, 44 | {'id': 'ip_address', 'type': 'string', 'mode': ''}, 45 | {'id': 'local_storage_active', 'type': 'boolean', 'mode': ''}, 46 | {'id': 'management_server_id', 'type': 'int', 'mode': ''}, 47 | ) 48 | 49 | _relations = BaseComponent._relations + ( 50 | ('cluster', ToOne(ToManyCont, 51 | 'ZenPacks.zenoss.CloudStack.Cluster.Cluster', 52 | 'hosts') 53 | ), 54 | 55 | ('systemvms', ToMany(ToOne, 56 | 'ZenPacks.zenoss.CloudStack.SystemVM.SystemVM', 57 | 'host') 58 | ), 59 | 60 | ('routervms', ToMany(ToOne, 61 | 'ZenPacks.zenoss.CloudStack.RouterVM.RouterVM', 62 | 'host') 63 | ), 64 | 65 | ('vms', ToMany(ToOne, 66 | 'ZenPacks.zenoss.CloudStack.VirtualMachine.VirtualMachine', 67 | 'host') 68 | ), 69 | ) 70 | 71 | _catalogs = { 72 | 'HostCatalog': { 73 | 'deviceclass': '/CloudStack', 74 | 'indexes': { 75 | 'ipv4_addresses': {'type': 'keyword'}, 76 | }, 77 | }, 78 | } 79 | 80 | @property 81 | def ipv4_addresses(self): 82 | return (self.ip_address,) 83 | 84 | @classmethod 85 | def findByIP(cls, dmd, ipv4_addresses): 86 | ''' 87 | Return the first Host matching one of ipv4_addresses. 88 | ''' 89 | return next(cls.search( 90 | dmd, 'HostCatalog', ipv4_addresses=ipv4_addresses), None) 91 | 92 | def device(self): 93 | return self.cluster().device() 94 | 95 | def getManagedDevice(self): 96 | device = self.findDevice(self.ip_address) 97 | if device: 98 | return device 99 | 100 | ip = self.getDmdRoot("Networks").findIp(self.ip_address) 101 | if ip: 102 | return ip.device() 103 | 104 | @require_zenpack('ZenPacks.zenoss.XenServer') 105 | def xenserver_host(self): 106 | from ZenPacks.zenoss.XenServer.PIF import PIF 107 | 108 | pif = PIF.findByIP(self.dmd, self.ipv4_addresses) 109 | if pif: 110 | return pif.host() 111 | -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/Pod.py: -------------------------------------------------------------------------------- 1 | ########################################################################### 2 | # 3 | # This program is part of Zenoss Core, an open source monitoring platform. 4 | # Copyright (C) 2011, 2012 Zenoss Inc. 5 | # 6 | # This program is free software; you can redistribute it and/or modify it 7 | # under the terms of the GNU General Public License version 2 or (at your 8 | # option) any later version as published by the Free Software Foundation. 9 | # 10 | # For complete information please visit: http://www.zenoss.com/oss/ 11 | # 12 | ########################################################################### 13 | 14 | from Products.ZenRelations.RelSchema import ToManyCont, ToOne 15 | 16 | from ZenPacks.zenoss.CloudStack import BaseComponent 17 | 18 | 19 | class Pod(BaseComponent): 20 | meta_type = portal_type = "CloudStackPod" 21 | 22 | start_ip = None 23 | end_ip = None 24 | netmask = None 25 | gateway = None 26 | 27 | _properties = BaseComponent._properties + ( 28 | {'id': 'start_ip', 'type': 'string', 'mode': ''}, 29 | {'id': 'end_ip', 'type': 'string', 'mode': ''}, 30 | {'id': 'netmask', 'type': 'string', 'mode': ''}, 31 | {'id': 'gateway', 'type': 'string', 'mode': ''}, 32 | ) 33 | 34 | _relations = BaseComponent._relations + ( 35 | ('zone', ToOne(ToManyCont, 36 | 'ZenPacks.zenoss.CloudStack.Zone.Zone', 37 | 'pods') 38 | ), 39 | 40 | ('clusters', ToManyCont(ToOne, 41 | 'ZenPacks.zenoss.CloudStack.Cluster.Cluster', 42 | 'pod') 43 | ), 44 | 45 | ('systemvms', ToManyCont(ToOne, 46 | 'ZenPacks.zenoss.CloudStack.SystemVM.SystemVM', 47 | 'pod') 48 | ), 49 | 50 | ('routervms', ToManyCont(ToOne, 51 | 'ZenPacks.zenoss.CloudStack.RouterVM.RouterVM', 52 | 'pod') 53 | ), 54 | ) 55 | 56 | def device(self): 57 | return self.zone().device() 58 | -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/RouterVM.py: -------------------------------------------------------------------------------- 1 | ########################################################################### 2 | # 3 | # This program is part of Zenoss Core, an open source monitoring platform. 4 | # Copyright (C) 2012-2013, Zenoss Inc. 5 | # 6 | # This program is free software; you can redistribute it and/or modify it 7 | # under the terms of the GNU General Public License version 2 or (at your 8 | # option) any later version as published by the Free Software Foundation. 9 | # 10 | # For complete information please visit: http://www.zenoss.com/oss/ 11 | # 12 | ########################################################################### 13 | 14 | from Products.ZenRelations.RelSchema import ToMany, ToManyCont, ToOne 15 | 16 | from ZenPacks.zenoss.CloudStack import BaseComponent, TouchTestMixin 17 | from ZenPacks.zenoss.CloudStack.utils import require_zenpack 18 | 19 | 20 | class RouterVM(BaseComponent, TouchTestMixin): 21 | meta_type = portal_type = "CloudStackRouterVM" 22 | 23 | account = None 24 | created = None 25 | dns1 = None 26 | dns2 = None 27 | domain = None 28 | gateway = None 29 | guest_ip = None 30 | guest_macaddress = None 31 | guest_netmask = None 32 | linklocal_ip = None 33 | linklocal_macaddress = None 34 | linklocal_netmask = None 35 | network_domain = None 36 | public_ip = None 37 | public_macaddress = None 38 | public_netmask = None 39 | state = None 40 | template_id = None 41 | 42 | _properties = BaseComponent._properties + ( 43 | {'id': 'account', 'type': 'string', 'mode': 'w'}, 44 | {'id': 'created', 'type': 'string', 'mode': 'w'}, 45 | {'id': 'dns1', 'type': 'string', 'mode': 'w'}, 46 | {'id': 'dns2', 'type': 'string', 'mode': 'w'}, 47 | {'id': 'domain', 'type': 'string', 'mode': 'w'}, 48 | {'id': 'gateway', 'type': 'string', 'mode': 'w'}, 49 | {'id': 'guest_ip', 'type': 'string', 'mode': 'w'}, 50 | {'id': 'guest_macaddress', 'type': 'string', 'mode': 'w'}, 51 | {'id': 'guest_netmask', 'type': 'string', 'mode': 'w'}, 52 | {'id': 'linklocal_ip', 'type': 'string', 'mode': 'w'}, 53 | {'id': 'linklocal_macaddress', 'type': 'string', 'mode': 'w'}, 54 | {'id': 'linklocal_netmask', 'type': 'string', 'mode': 'w'}, 55 | {'id': 'network_domain', 'type': 'string', 'mode': 'w'}, 56 | {'id': 'public_ip', 'type': 'string', 'mode': 'w'}, 57 | {'id': 'public_macaddress', 'type': 'string', 'mode': 'w'}, 58 | {'id': 'public_netmask', 'type': 'string', 'mode': 'w'}, 59 | {'id': 'state', 'type': 'string', 'mode': 'w'}, 60 | {'id': 'template_id', 'type': 'int', 'mode': 'w'}, 61 | ) 62 | 63 | _relations = BaseComponent._relations + ( 64 | ('pod', ToOne(ToManyCont, 65 | 'ZenPacks.zenoss.CloudStack.Pod.Pod', 66 | 'routervms') 67 | ), 68 | 69 | ('host', ToOne(ToMany, 70 | 'ZenPacks.zenoss.CloudStack.Host.Host', 71 | 'routervms') 72 | ), 73 | ) 74 | 75 | _catalogs = { 76 | 'RouterVMCatalog': { 77 | 'deviceclass': '/CloudStack', 78 | 'indexes': { 79 | 'ipv4_addresses': {'type': 'keyword'}, 80 | 'mac_addresses': {'type': 'keyword'}, 81 | }, 82 | }, 83 | } 84 | 85 | @property 86 | def ipv4_addresses(self): 87 | return filter( 88 | lambda x: x, ( 89 | self.guest_ip, 90 | self.linklocal_ip, 91 | self.public_ip)) 92 | 93 | @property 94 | def mac_addresses(self): 95 | return filter( 96 | lambda x: x, ( 97 | self.guest_macaddress, 98 | self.linklocal_macaddress, 99 | self.public_macaddress)) 100 | 101 | @classmethod 102 | def findByIP(cls, dmd, ipv4_addresses): 103 | ''' 104 | Return the first RouterVM matching one of ipv4_addresses. 105 | ''' 106 | return next(cls.search( 107 | dmd, 'RouterVMCatalog', ipv4_addresses=ipv4_addresses), None) 108 | 109 | @classmethod 110 | def findByMAC(cls, dmd, mac_addresses): 111 | ''' 112 | Return the first RouterVM matching one of mac_addresses. 113 | ''' 114 | return next(cls.search( 115 | dmd, 'RouterVMCatalog', mac_addresses=mac_addresses), None) 116 | 117 | def device(self): 118 | return self.pod().device() 119 | 120 | def setHostId(self, host_id): 121 | for cluster in self.pod.clusters(): 122 | for host in cluster.hosts(): 123 | if host_id == host.cloudstack_id: 124 | self.host.addRelation(host) 125 | return 126 | 127 | def getHostId(self): 128 | host = self.host() 129 | if host: 130 | return host.cloudstack_id 131 | 132 | def getRRDTemplates(self): 133 | templates = super(BaseComponent, self).getRRDTemplates() 134 | templates.extend(self.extra_templates()) 135 | 136 | return templates 137 | 138 | @require_zenpack('ZenPacks.zenoss.XenServer') 139 | def xenserver_vm(self): 140 | from ZenPacks.zenoss.XenServer.VIF import VIF 141 | 142 | vif = VIF.findByMAC(self.dmd, mac_addresses=self.mac_addresses) 143 | if vif: 144 | return vif.vm() 145 | -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/SystemVM.py: -------------------------------------------------------------------------------- 1 | ########################################################################### 2 | # 3 | # This program is part of Zenoss Core, an open source monitoring platform. 4 | # Copyright (C) 2012-2013, Zenoss Inc. 5 | # 6 | # This program is free software; you can redistribute it and/or modify it 7 | # under the terms of the GNU General Public License version 2 or (at your 8 | # option) any later version as published by the Free Software Foundation. 9 | # 10 | # For complete information please visit: http://www.zenoss.com/oss/ 11 | # 12 | ########################################################################### 13 | 14 | from Products.ZenRelations.RelSchema import ToMany, ToManyCont, ToOne 15 | 16 | from ZenPacks.zenoss.CloudStack import BaseComponent, TouchTestMixin 17 | from ZenPacks.zenoss.CloudStack.utils import require_zenpack 18 | 19 | 20 | class SystemVM(BaseComponent, TouchTestMixin): 21 | meta_type = portal_type = "CloudStackSystemVM" 22 | 23 | gateway = None 24 | linklocal_ip = None 25 | linklocal_macaddress = None 26 | linklocal_netmask = None 27 | network_domain = None 28 | private_ip = None 29 | private_macaddress = None 30 | private_netmask = None 31 | public_ip = None 32 | public_macaddress = None 33 | public_netmask = None 34 | systemvm_type = None 35 | template_id = None 36 | 37 | _properties = BaseComponent._properties + ( 38 | {'id': 'gateway', 'type': 'string', 'mode': 'w'}, 39 | {'id': 'linklocal_ip', 'type': 'string', 'mode': 'w'}, 40 | {'id': 'linklocal_macaddress', 'type': 'string', 'mode': 'w'}, 41 | {'id': 'linklocal_netmask', 'type': 'string', 'mode': 'w'}, 42 | {'id': 'network_domain', 'type': 'string', 'mode': 'w'}, 43 | {'id': 'private_ip', 'type': 'string', 'mode': 'w'}, 44 | {'id': 'private_macaddress', 'type': 'string', 'mode': 'w'}, 45 | {'id': 'private_netmask', 'type': 'string', 'mode': 'w'}, 46 | {'id': 'public_ip', 'type': 'string', 'mode': 'w'}, 47 | {'id': 'public_macaddress', 'type': 'string', 'mode': 'w'}, 48 | {'id': 'public_netmask', 'type': 'string', 'mode': 'w'}, 49 | {'id': 'systemvm_type', 'type': 'string', 'mode': 'w'}, 50 | {'id': 'template_id', 'type': 'int', 'mode': 'w'}, 51 | ) 52 | 53 | _relations = BaseComponent._relations + ( 54 | ('pod', ToOne(ToManyCont, 55 | 'ZenPacks.zenoss.CloudStack.Pod.Pod', 56 | 'systemvms') 57 | ), 58 | 59 | ('host', ToOne(ToMany, 60 | 'ZenPacks.zenoss.CloudStack.Host.Host', 61 | 'systemvms') 62 | ), 63 | ) 64 | 65 | _catalogs = { 66 | 'SystemVMCatalog': { 67 | 'deviceclass': '/CloudStack', 68 | 'indexes': { 69 | 'ipv4_addresses': {'type': 'keyword'}, 70 | 'mac_addresses': {'type': 'keyword'}, 71 | }, 72 | }, 73 | } 74 | 75 | @property 76 | def ipv4_addresses(self): 77 | return filter( 78 | lambda x: x, ( 79 | self.linklocal_ip, 80 | self.private_ip, 81 | self.public_ip)) 82 | 83 | @property 84 | def mac_addresses(self): 85 | return filter( 86 | lambda x: x, ( 87 | self.linklocal_macaddress, 88 | self.private_macaddress, 89 | self.public_macaddress)) 90 | 91 | @classmethod 92 | def findByIP(cls, dmd, ipv4_addresses): 93 | ''' 94 | Return the first SystemVM matching one of ipv4_addresses. 95 | ''' 96 | return next(cls.search( 97 | dmd, 'SystemVMCatalog', ipv4_addresses=ipv4_addresses), None) 98 | 99 | @classmethod 100 | def findByMAC(cls, dmd, mac_addresses): 101 | ''' 102 | Return the first SystemVM matching one of mac_addresses. 103 | ''' 104 | return next(cls.search( 105 | dmd, 'SystemVMCatalog', mac_addresses=mac_addresses), None) 106 | 107 | def device(self): 108 | return self.pod().device() 109 | 110 | def setHostId(self, host_id): 111 | for cluster in self.pod.clusters(): 112 | for host in cluster.hosts(): 113 | if host_id == host.cloudstack_id: 114 | self.host.addRelation(host) 115 | return 116 | 117 | def getHostId(self): 118 | host = self.host() 119 | if host: 120 | return host.cloudstack_id 121 | 122 | def getRRDTemplates(self): 123 | templates = super(BaseComponent, self).getRRDTemplates() 124 | templates.extend(self.extra_templates()) 125 | 126 | if self.systemvm_type == 'consoleproxy': 127 | console_proxy = self.getRRDTemplateByName('CloudStackConsoleProxy') 128 | if console_proxy: 129 | templates.append(console_proxy) 130 | 131 | return templates 132 | 133 | @require_zenpack('ZenPacks.zenoss.XenServer') 134 | def xenserver_vm(self): 135 | from ZenPacks.zenoss.XenServer.VIF import VIF 136 | 137 | vif = VIF.findByMAC(self.dmd, mac_addresses=self.mac_addresses) 138 | if vif: 139 | return vif.vm() 140 | -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/VirtualMachine.py: -------------------------------------------------------------------------------- 1 | ########################################################################### 2 | # 3 | # This program is part of Zenoss Core, an open source monitoring platform. 4 | # Copyright (C) 2012-2013, Zenoss Inc. 5 | # 6 | # This program is free software; you can redistribute it and/or modify it 7 | # under the terms of the GNU General Public License version 2 or (at your 8 | # option) any later version as published by the Free Software Foundation. 9 | # 10 | # For complete information please visit: http://www.zenoss.com/oss/ 11 | # 12 | ########################################################################### 13 | 14 | from Products.ZenRelations.RelSchema import ToMany, ToManyCont, ToOne 15 | 16 | from ZenPacks.zenoss.CloudStack import BaseComponent 17 | from ZenPacks.zenoss.CloudStack.utils import require_zenpack 18 | 19 | 20 | class VirtualMachine(BaseComponent): 21 | meta_type = portal_type = "CloudStackVirtualMachine" 22 | 23 | account = None 24 | cpu_number = None 25 | cpu_speed = None 26 | created = None 27 | display_name = None 28 | domain = None 29 | ha_enable = None 30 | memory = None 31 | mac_address = None 32 | ip_address = None 33 | netmask = None 34 | gateway = None 35 | root_device_type = None 36 | service_offering = None 37 | state = None 38 | template = None 39 | 40 | _properties = BaseComponent._properties + ( 41 | {'id': 'account', 'type': 'string', 'mode': 'w'}, 42 | {'id': 'cpu_number', 'type': 'int', 'mode': 'w'}, 43 | {'id': 'cpu_speed', 'type': 'int', 'mode': 'w'}, 44 | {'id': 'created', 'type': 'string', 'mode': 'w'}, 45 | {'id': 'display_name', 'type': 'string', 'mode': 'w'}, 46 | {'id': 'domain', 'type': 'string', 'mode': 'w'}, 47 | {'id': 'ha_enable', 'type': 'boolean', 'mode': 'w'}, 48 | {'id': 'memory', 'type': 'int', 'mode': 'w'}, 49 | {'id': 'mac_address', 'type': 'string', 'mode': 'w'}, 50 | {'id': 'ip_address', 'type': 'string', 'mode': 'w'}, 51 | {'id': 'netmask', 'type': 'string', 'mode': 'w'}, 52 | {'id': 'gateway', 'type': 'string', 'mode': 'w'}, 53 | {'id': 'root_device_type', 'type': 'string', 'mode': 'w'}, 54 | {'id': 'service_offering', 'type': 'string', 'mode': 'w'}, 55 | {'id': 'state', 'type': 'string', 'mode': 'w'}, 56 | {'id': 'template', 'type': 'string', 'mode': 'w'}, 57 | ) 58 | 59 | _relations = BaseComponent._relations + ( 60 | ('zone', ToOne(ToManyCont, 61 | 'ZenPacks.zenoss.CloudStack.Zone.Zone', 62 | 'vms') 63 | ), 64 | 65 | ('host', ToOne(ToMany, 66 | 'ZenPacks.zenoss.CloudStack.Host.Host', 67 | 'vms') 68 | ), 69 | ) 70 | 71 | _catalogs = { 72 | 'VirtualMachineCatalog': { 73 | 'deviceclass': '/CloudStack', 74 | 'indexes': { 75 | 'ipv4_addresses': {'type': 'keyword'}, 76 | 'mac_addresses': {'type': 'keyword'}, 77 | }, 78 | }, 79 | } 80 | 81 | @property 82 | def ipv4_addresses(self): 83 | return (self.ip_address,) 84 | 85 | @property 86 | def mac_addresses(self): 87 | return (self.mac_address,) 88 | 89 | @classmethod 90 | def findByIP(cls, dmd, ipv4_addresses): 91 | ''' 92 | Return the first VirtualMachine matching one of ipv4_addresses. 93 | ''' 94 | return next(cls.search( 95 | dmd, 'VirtualMachineCatalog', ipv4_addresses=ipv4_addresses), None) 96 | 97 | @classmethod 98 | def findByMAC(cls, dmd, mac_addresses): 99 | ''' 100 | Return the first VirtualMachine matching one of mac_addresses. 101 | ''' 102 | return next(cls.search( 103 | dmd, 'VirtualMachineCatalog', mac_addresses=mac_addresses), None) 104 | 105 | def device(self): 106 | zone = self.zone() 107 | if not zone: 108 | zone = self.getPrimaryParent().getPrimaryParent() 109 | 110 | return zone.device() 111 | 112 | def setHostId(self, host_id): 113 | for pod in self.zone().pods(): 114 | for cluster in pod.clusters(): 115 | for host in cluster.hosts(): 116 | if host_id == host.cloudstack_id: 117 | self.host.addRelation(host) 118 | return 119 | 120 | def getHostId(self): 121 | host = self.host() 122 | if host: 123 | return host.cloudstack_id 124 | 125 | def getManagedDevice(self): 126 | device = self.findDevice(self.ip_address) 127 | if device: 128 | return device 129 | 130 | ip = self.getDmdRoot("Networks").findIp(self.ip_address) 131 | if ip: 132 | return ip.device() 133 | 134 | @require_zenpack('ZenPacks.zenoss.XenServer') 135 | def xenserver_vm(self): 136 | from ZenPacks.zenoss.XenServer.VIF import VIF 137 | 138 | vif = VIF.findByMAC(self.dmd, mac_addresses=self.mac_addresses) 139 | if vif: 140 | return vif.vm() 141 | -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/Zone.py: -------------------------------------------------------------------------------- 1 | ########################################################################### 2 | # 3 | # This program is part of Zenoss Core, an open source monitoring platform. 4 | # Copyright (C) 2011, Zenoss Inc. 5 | # 6 | # This program is free software; you can redistribute it and/or modify it 7 | # under the terms of the GNU General Public License version 2 or (at your 8 | # option) any later version as published by the Free Software Foundation. 9 | # 10 | # For complete information please visit: http://www.zenoss.com/oss/ 11 | # 12 | ########################################################################### 13 | 14 | from Products.ZenRelations.RelSchema import ToManyCont, ToOne 15 | 16 | from ZenPacks.zenoss.CloudStack import BaseComponent 17 | 18 | 19 | class Zone(BaseComponent): 20 | meta_type = portal_type = "CloudStackZone" 21 | 22 | guest_cidr_address = None 23 | dhcp_provider = None 24 | dns1 = None 25 | dns2 = None 26 | internal_dns1 = None 27 | internal_dns2 = None 28 | network_type = None 29 | security_groups_enabled = None 30 | vlan = None 31 | zone_token = None 32 | 33 | _properties = BaseComponent._properties + ( 34 | {'id': 'guest_cidr_address', 'type': 'string', 'mode': ''}, 35 | {'id': 'dhcp_provider', 'type': 'string', 'mode': ''}, 36 | {'id': 'dns1', 'type': 'string', 'mode': ''}, 37 | {'id': 'dns2', 'type': 'string', 'mode': ''}, 38 | {'id': 'internal_dns1', 'type': 'string', 'mode': ''}, 39 | {'id': 'internal_dns2', 'type': 'string', 'mode': ''}, 40 | {'id': 'network_type', 'type': 'string', 'mode': ''}, 41 | {'id': 'security_groups_enabled', 'type': 'boolean', 'mode': ''}, 42 | {'id': 'vlan', 'type': 'string', 'mode': ''}, 43 | {'id': 'zone_token', 'type': 'string', 'mode': ''}, 44 | ) 45 | 46 | _relations = BaseComponent._relations + ( 47 | ('cloud', ToOne(ToManyCont, 48 | 'ZenPacks.zenoss.CloudStack.Cloud.Cloud', 49 | 'zones') 50 | ), 51 | 52 | ('pods', ToManyCont(ToOne, 53 | 'ZenPacks.zenoss.CloudStack.Pod.Pod', 54 | 'zone') 55 | ), 56 | 57 | ('vms', ToManyCont(ToOne, 58 | 'ZenPacks.zenoss.CloudStack.VirtualMachine.VirtualMachine', 59 | 'zone') 60 | ), 61 | ) 62 | 63 | def device(self): 64 | return self.cloud() 65 | 66 | 67 | def getRRDTemplates(self): 68 | templates = super(Zone, self).getRRDTemplates() 69 | if not self.isRootAdmin(): 70 | return [] 71 | 72 | return templates 73 | -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/__init__.py: -------------------------------------------------------------------------------- 1 | ########################################################################### 2 | # 3 | # This program is part of Zenoss Core, an open source monitoring platform. 4 | # Copyright (C) 2011, 2013, Zenoss Inc. 5 | # 6 | # This program is free software; you can redistribute it and/or modify it 7 | # under the terms of the GNU General Public License version 2 or (at your 8 | # option) any later version as published by the Free Software Foundation. 9 | # 10 | # For complete information please visit: http://www.zenoss.com/oss/ 11 | # 12 | ########################################################################### 13 | 14 | import logging 15 | LOG = logging.getLogger('zen.CloudStack') 16 | 17 | import os 18 | 19 | import Globals 20 | 21 | from Products.ZenEvents.EventManagerBase import EventManagerBase 22 | from Products.ZenModel.DeviceComponent import DeviceComponent 23 | from Products.ZenModel.ManagedEntity import ManagedEntity 24 | from Products.ZenModel.ZenossSecurity import ZEN_CHANGE_DEVICE 25 | from Products.ZenModel.ZenPack import ZenPack as ZenPackBase 26 | from Products.ZenRelations.zPropertyCategory import setzPropertyCategory 27 | from Products.ZenUtils.Search import makeFieldIndex, makeKeywordIndex 28 | from Products.ZenUtils.Utils import zenPath, unused 29 | 30 | unused(Globals) 31 | 32 | 33 | ZENPACK_NAME = 'ZenPacks.zenoss.CloudStack' 34 | 35 | # Modules containing model classes. Used by zenchkschema to validate 36 | # bidirectional integrity of defined relationships. 37 | productNames = ( 38 | 'Cloud', 39 | 'Cluster', 40 | 'Host', 41 | 'Pod', 42 | 'RouterVM', 43 | 'SystemVM', 44 | 'VirtualMachine', 45 | 'Zone', 46 | ) 47 | 48 | # Useful to avoid making literal string references to module and class names 49 | # throughout the rest of the ZenPack. 50 | MODULE_NAME = {} 51 | CLASS_NAME = {} 52 | 53 | for product_name in productNames: 54 | MODULE_NAME[product_name] = '.'.join([ZENPACK_NAME, product_name]) 55 | CLASS_NAME[product_name] = '.'.join([ZENPACK_NAME, product_name, product_name]) 56 | 57 | setzPropertyCategory('zCloudStackURL', 'CloudStack') 58 | setzPropertyCategory('zCloudStackAPIKey', 'CloudStack') 59 | setzPropertyCategory('zCloudStackSecretKey', 'CloudStack') 60 | 61 | 62 | class ZenPack(ZenPackBase): 63 | packZProperties = [ 64 | ('zCloudStackURL', '', 'string'), 65 | ('zCloudStackAPIKey', '', 'string'), 66 | ('zCloudStackSecretKey', '', 'password'), 67 | ] 68 | 69 | _plugins = ( 70 | 'poll_cloudstack.py', 71 | ) 72 | 73 | def install(self, app): 74 | # We expect the /Capacity event class to exist, but don't want to add 75 | # it into objects.xml in case someone removes this ZenPack. 76 | app.zport.dmd.Events.createOrganizer('/Capacity') 77 | 78 | super(ZenPack, self).install(app) 79 | self.symlink_plugins() 80 | 81 | def remove(self, app, leaveObjects=False): 82 | if not leaveObjects: 83 | self.remove_plugin_symlinks() 84 | 85 | super(ZenPack, self).remove(app, leaveObjects=leaveObjects) 86 | 87 | def symlink_plugins(self): 88 | libexec = os.path.join(os.environ.get('ZENHOME'), 'libexec') 89 | if not os.path.isdir(libexec): 90 | # Stack installs might not have a $ZENHOME/libexec directory. 91 | os.mkdir(libexec) 92 | 93 | for plugin in self._plugins: 94 | LOG.info('Linking %s plugin into $ZENHOME/libexec/', plugin) 95 | plugin_path = zenPath('libexec', plugin) 96 | os.system('ln -sf "%s" "%s"' % (self.path(plugin), plugin_path)) 97 | os.system('chmod 0755 %s' % plugin_path) 98 | 99 | def remove_plugin_symlinks(self): 100 | for plugin in self._plugins: 101 | LOG.info('Removing %s link from $ZENHOME/libexec/', plugin) 102 | os.system('rm -f "%s"' % zenPath('libexec', plugin)) 103 | 104 | 105 | class CatalogMixin(object): 106 | ''' 107 | Abstract class mixin to ease the creation and use of 108 | component-specific catalogs. 109 | 110 | To use this mixin to create a component catalog you should define 111 | a _catalog property such as the following on your mixed-in class:: 112 | 113 | _catalogs = dict({ 114 | 'catalogName', { 115 | 'deviceclass': '/Example/Device/Class', 116 | 'indexes': { 117 | 'ipv4_addresses': {'type': 'keyword'}, 118 | 'mac_addresses': {'type': 'keyword'}, 119 | }, 120 | }, 121 | }, **BaseClass._catalogs) 122 | 123 | The second item in each indexes tuple can either be keyword or 124 | field. These correspond to Zope case-insensitive KeywordIndex and 125 | FieldIndex. 126 | ''' 127 | 128 | _catalogs = {} 129 | 130 | @classmethod 131 | def _catalog_spec(cls, name): 132 | spec = cls._catalogs.get(name) 133 | if not spec: 134 | LOG.error("%s catalog definition is missing", name) 135 | return 136 | 137 | if not isinstance(spec, dict): 138 | LOG.error("%s catalog definition is not a dict", name) 139 | return 140 | 141 | if not spec.get('indexes'): 142 | LOG.error("%s catalog definition has no indexes", name) 143 | return 144 | 145 | if not spec.get('deviceclass'): 146 | LOG.error("%s catalog definition has no deviceclass.", name) 147 | return 148 | 149 | return spec 150 | 151 | @classmethod 152 | def _create_catalog(cls, dmd, name): 153 | from Products.ZCatalog.Catalog import CatalogError 154 | from Products.ZCatalog.ZCatalog import manage_addZCatalog 155 | 156 | from Products.Zuul.interfaces import ICatalogTool 157 | 158 | spec = cls._catalog_spec(name) 159 | if not spec: 160 | return 161 | 162 | deviceclass = dmd.Devices.createOrganizer(spec['deviceclass']) 163 | 164 | if not hasattr(deviceclass, name): 165 | manage_addZCatalog(deviceclass, name, name) 166 | 167 | zcatalog = deviceclass._getOb(name) 168 | catalog = zcatalog._catalog 169 | 170 | for propname, propdata in spec['indexes'].items(): 171 | index_type = propdata.get('type') 172 | if not index_type: 173 | LOG.error("%s index has no type", propname) 174 | return 175 | 176 | index_factory = { 177 | 'field': makeFieldIndex, 178 | 'keyword': makeKeywordIndex, 179 | }.get(index_type.lower()) 180 | 181 | if not index_factory: 182 | LOG.error("%s is not a valid index type", index_type) 183 | return 184 | 185 | try: 186 | catalog.addIndex(propname, index_factory(propname)) 187 | except CatalogError: 188 | # Index already exists. 189 | pass 190 | else: 191 | fqcn = '.'.join((cls.__module__, cls.__name__)) 192 | results = ICatalogTool(dmd.primaryAq()).search(fqcn) 193 | for brain in results: 194 | brain.getObject().index_object() 195 | 196 | return zcatalog 197 | 198 | @classmethod 199 | def _get_catalog(cls, dmd, name): 200 | spec = cls._catalog_spec(name) 201 | if not spec: 202 | return 203 | 204 | deviceclass = dmd.Devices.createOrganizer(spec['deviceclass']) 205 | 206 | try: 207 | return getattr(deviceclass, name) 208 | except AttributeError: 209 | return cls._create_catalog(dmd, name) 210 | 211 | @classmethod 212 | def search(cls, dmd, name, **kwargs): 213 | ''' 214 | Generate instances of this object that match keyword arguments. 215 | ''' 216 | catalog = cls._get_catalog(dmd, name) 217 | if not catalog: 218 | return 219 | 220 | for brain in catalog(**kwargs): 221 | yield brain.getObject() 222 | 223 | def index_object(self, idxs=None): 224 | ''' 225 | Index the mixed-in instance in its catalogs. 226 | 227 | We rely on subclasses to explicitely call this method in 228 | addition to their primary inheritence index_object method as in 229 | the following override:: 230 | 231 | def index_object(self, idxs=None): 232 | for superclass in (ManagedEntity, CatalogMixin): 233 | superclass.index_object(self, idxs=idxs) 234 | ''' 235 | for catalog in (self._get_catalog(self.dmd, x) for x in self._catalogs): 236 | catalog.catalog_object(self, self.getPrimaryId()) 237 | 238 | def unindex_object(self): 239 | ''' 240 | Unindex the mixed-in instance from its catalogs. 241 | 242 | We rely on subclasses to explicitely call this method in 243 | addition to their primary inheritence unindex_object method as 244 | in the following override:: 245 | 246 | def unindex_object(self): 247 | for superclass in (ManagedEntity, CatalogMixin): 248 | superclass.unindex_object(self) 249 | ''' 250 | for catalog in (self._get_catalog(self.dmd, x) for x in self._catalogs): 251 | catalog.uncatalog_object(self.getPrimaryId()) 252 | 253 | 254 | class BaseComponent(DeviceComponent, ManagedEntity, CatalogMixin): 255 | """ 256 | Abstract base class to avoid repeating boilerplate code in all of the 257 | DeviceComponent subclasses in this ZenPack. 258 | """ 259 | 260 | # All CloudStack components have these properties. 261 | cloudstack_id = None 262 | allocation_state = None 263 | 264 | _properties = ManagedEntity._properties + ( 265 | {'id': 'cloudstack_id', 'type': 'int', 'mode': ''}, 266 | {'id': 'allocation_state', 'type': 'string', 'mode': ''}, 267 | ) 268 | 269 | # Disambiguate multi-inheritence. 270 | _relations = ManagedEntity._relations 271 | 272 | # This makes the "Templates" component display available. 273 | factory_type_information = ({ 274 | 'actions': ({ 275 | 'id': 'perfConf', 276 | 'name': 'Template', 277 | 'action': 'objTemplates', 278 | 'permissions': (ZEN_CHANGE_DEVICE,), 279 | },), 280 | },) 281 | 282 | # Query for events by id instead of name. 283 | event_key = "ComponentId" 284 | 285 | def index_object(self, idxs=None): 286 | ''' 287 | Index object according to ManagedEntity and CatalogMixin. 288 | ''' 289 | for superclass in (ManagedEntity, CatalogMixin): 290 | superclass.index_object(self, idxs=idxs) 291 | 292 | def unindex_object(self): 293 | ''' 294 | Unindex object according to ManagedEntity and CatalogMixin. 295 | ''' 296 | for superclass in (ManagedEntity, CatalogMixin): 297 | superclass.unindex_object(self) 298 | 299 | def getIconPath(self): 300 | return '/++resource++cloudstack/img/cloudstack.png' 301 | 302 | 303 | class TouchTestMixin(object): 304 | """Common code for objects that support a "touch test".""" 305 | 306 | def ssh_prefix(self): 307 | """SSH prefix for connecting to system VMs through their host. 308 | 309 | This is necessary because system VMs are only able to be connected to 310 | via SSH through their link-local IP address. The only server that can 311 | reach the link-local IP is the host that the VM is currently running on. 312 | 313 | """ 314 | 315 | host_ip = None 316 | host = self.host() 317 | if host and host.ip_address: 318 | host_ip = host.ip_address 319 | else: 320 | # From TEST-NET. Should never be a real IP address. 321 | host_ip = '192.0.2.1' 322 | 323 | key_option = None 324 | if self.primaryAq().zKeyPath: 325 | key_option = '-i %s' % self.primaryAq().zKeyPath 326 | else: 327 | key_option = '' 328 | 329 | user_prefix = None 330 | if self.primaryAq().zCommandUsername: 331 | user_prefix = '%s@' % self.primaryAq().zCommandUsername 332 | else: 333 | user_prefix = '' 334 | 335 | connect_timeout = None 336 | if self.primaryAq().zCommandCommandTimeout: 337 | connect_timeout = int(self.primaryAq().zCommandCommandTimeout) / 2 338 | else: 339 | connect_timeout = 30 340 | 341 | ssh_options = ( 342 | "-q ", 343 | "-o ConnectTimeout=%s" % connect_timeout, 344 | "-o StrictHostKeyChecking=no", 345 | "-o UserKnownHostsFile=/dev/null", 346 | ) 347 | 348 | context = { 349 | 'key_option': key_option, 350 | 'user_prefix': user_prefix, 351 | 'ssh_options': ' '.join(ssh_options), 352 | 'host_ip': host_ip, 353 | 'linklocal_ip': self.linklocal_ip, 354 | } 355 | 356 | return ( 357 | "ssh %(key_option)s %(ssh_options)s " 358 | "%(user_prefix)s%(host_ip)s " 359 | "ssh -i /root/.ssh/id_rsa.cloud -p3922 %(ssh_options)s " 360 | "root@%(linklocal_ip)s" % context) 361 | 362 | def touch_test_command(self): 363 | """Command template for touching and removing a file.""" 364 | return ( 365 | '/usr/bin/env sh -c \'' 366 | '%s "touch zenosstest \&\& rm zenosstest" ' 367 | '&& echo "file touched successfully" || ' 368 | '(echo "file touch failed" ; false)\' ' 369 | '2>/dev/null' % self.ssh_prefix()) 370 | 371 | def extra_templates(self): 372 | templates = [] 373 | 374 | host = self.host() 375 | if host and host.hypervisor == 'KVM': 376 | file_touch = self.getRRDTemplateByName("CloudStackFileTouch") 377 | if file_touch: 378 | templates.append(file_touch) 379 | 380 | return templates 381 | 382 | 383 | # We need to filter CloudStack components by id instead of name. 384 | EventManagerBase.ComponentIdWhere = ( 385 | "\"(device = '%s' and component = '%s')\"" 386 | " % (me.device().getDmdKey(), me.id)") 387 | -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/browser/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenoss/ZenPacks.zenoss.CloudStack/a3156e7f13f3cd04a4cbc588c3d36d036b696a34/ZenPacks/zenoss/CloudStack/browser/__init__.py -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/browser/configure.zcml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 17 | 18 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/browser/resources/img/cloudstack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenoss/ZenPacks.zenoss.CloudStack/a3156e7f13f3cd04a4cbc588c3d36d036b696a34/ZenPacks/zenoss/CloudStack/browser/resources/img/cloudstack.png -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/browser/resources/js/cloudstack.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 3 | var add_cloudstack = new Zenoss.Action({ 4 | text: _t('Add CloudStack') + '...', 5 | id: 'addcloudstack-item', 6 | permission: 'Manage DMD', 7 | handler: function(btn, e){ 8 | var win = new Zenoss.dialog.CloseDialog({ 9 | width: 300, 10 | title: _t('Add CloudStack'), 11 | items: [{ 12 | xtype: 'form', 13 | buttonAlign: 'left', 14 | monitorValid: true, 15 | labelAlign: 'top', 16 | footerStyle: 'padding-left: 0', 17 | border: false, 18 | items: [{ 19 | xtype: 'textfield', 20 | name: 'device_name', 21 | fieldLabel: _t('Device to Create'), 22 | id: "cloudstackDeviceNameField", 23 | width: 260, 24 | allowBlank: false 25 | },{ 26 | xtype: 'textfield', 27 | name: 'url', 28 | fieldLabel: _t('URL'), 29 | id: "cloudstackURLField", 30 | width: 260, 31 | allowBlank: false 32 | }, { 33 | xtype: 'textfield', 34 | name: 'api_key', 35 | fieldLabel: _t('API Key'), 36 | id: "cloudstackAPIKeyField", 37 | width: 260, 38 | allowBlank: false 39 | }, { 40 | xtype: 'password', 41 | name: 'secret_key', 42 | fieldLabel: _t('Secret Key'), 43 | id: "cloudstackSecretKeyField", 44 | width: 260, 45 | allowBlank: false 46 | }, { 47 | xtype: 'combo', 48 | width: 260, 49 | name: 'collector', 50 | fieldLabel: _t('Collector'), 51 | id: 'add_smisprovider-collector', 52 | mode: 'local', 53 | store: new Ext.data.ArrayStore({ 54 | data: Zenoss.env.COLLECTORS, 55 | fields: ['name'] 56 | }), 57 | valueField: 'name', 58 | displayField: 'name', 59 | forceSelection: true, 60 | editable: false, 61 | allowBlank: false, 62 | triggerAction: 'all', 63 | selectOnFocus: false, 64 | listeners: { 65 | 'afterrender': function(component) { 66 | var index = component.store.find('name', 'localhost'); 67 | if (index >= 0) { 68 | component.setValue('localhost'); 69 | } 70 | } 71 | } 72 | }], 73 | buttons: [{ 74 | xtype: 'DialogButton', 75 | id: 'addCloudStackdevice-submit', 76 | text: _t('Add'), 77 | formBind: true, 78 | handler: function(b) { 79 | var form = b.ownerCt.ownerCt.getForm(); 80 | var opts = form.getFieldValues(); 81 | 82 | Zenoss.remote.CloudStackRouter.add_cloudstack(opts, 83 | function(response) { 84 | if (response.success) { 85 | if (Zenoss.JobsWidget) { 86 | Zenoss.message.success(_t('Add CloudStack job submitted.')); 87 | } else { 88 | Zenoss.message.success( 89 | _t('Add CloudStack job submitted. View Job Log'), 90 | response.jobId); 91 | } 92 | } 93 | else { 94 | Zenoss.message.error(_t('Error adding CloudStack: {0}'), 95 | response.msg); 96 | } 97 | }); 98 | } 99 | }, Zenoss.dialog.CANCEL] 100 | }] 101 | }); 102 | win.show(); 103 | } 104 | }); 105 | 106 | // Push the addOpenStack action to the adddevice button 107 | Ext.ns('Zenoss.extensions'); 108 | Zenoss.extensions.adddevice = Zenoss.extensions.adddevice instanceof Array ? 109 | Zenoss.extensions.adddevice : []; 110 | Zenoss.extensions.adddevice.push(add_cloudstack); 111 | 112 | }()); 113 | -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/configure.zcml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 18 | 19 | 25 | 26 | 27 | 32 | 33 | 34 | 39 | 40 | 45 | 46 | 51 | 52 | 57 | 58 | 63 | 64 | 69 | 70 | 75 | 76 | 81 | 82 | 83 | 84 | 85 | 86 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 101 | 102 | 107 | 108 | 113 | 114 | 119 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/deviceloaders.py: -------------------------------------------------------------------------------- 1 | ########################################################################### 2 | # 3 | # This program is part of Zenoss Core, an open source monitoring platform. 4 | # Copyright (C) 2011, Zenoss Inc. 5 | # 6 | # This program is free software; you can redistribute it and/or modify it 7 | # under the terms of the GNU General Public License version 2 or (at your 8 | # option) any later version as published by the Free Software Foundation. 9 | # 10 | # For complete information please visit: http://www.zenoss.com/oss/ 11 | # 12 | ########################################################################### 13 | 14 | from zope.interface import implements 15 | 16 | from Products.Zuul import getFacade 17 | from Products.ZenModel.interfaces import IDeviceLoader 18 | 19 | 20 | class CloudStackLoader(object): 21 | """Device loader for CloudStack ZenPack.""" 22 | 23 | implements(IDeviceLoader) 24 | 25 | def load_device(self, dmd, device_name, url, api_key, secret_key): 26 | return getFacade('cloudstack', dmd).add_cloudstack( 27 | device_name, url, api_key, secret_key) 28 | -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/dynamicview/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenoss/ZenPacks.zenoss.CloudStack/a3156e7f13f3cd04a4cbc588c3d36d036b696a34/ZenPacks/zenoss/CloudStack/dynamicview/__init__.py -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/dynamicview/adapters.py: -------------------------------------------------------------------------------- 1 | ########################################################################### 2 | # 3 | # This program is part of Zenoss Core, an open source monitoring platform. 4 | # Copyright (C) 2011, Zenoss Inc. 5 | # 6 | # This program is free software; you can redistribute it and/or modify it 7 | # under the terms of the GNU General Public License version 2 or (at your 8 | # option) any later version as published by the Free Software Foundation. 9 | # 10 | # For complete information please visit: http://www.zenoss.com/oss/ 11 | # 12 | ########################################################################### 13 | 14 | from zope.component import adapts 15 | 16 | from ZenPacks.zenoss.DynamicView import TAG_IMPACTED_BY, TAG_IMPACTS, TAG_ALL 17 | from ZenPacks.zenoss.DynamicView.model.adapters import BaseRelatable 18 | from ZenPacks.zenoss.DynamicView.model.adapters import BaseRelationsProvider 19 | from ZenPacks.zenoss.DynamicView.model.adapters import DeviceComponentRelatable 20 | 21 | from ZenPacks.zenoss.CloudStack.Cloud import Cloud 22 | from ZenPacks.zenoss.CloudStack.Zone import Zone 23 | from ZenPacks.zenoss.CloudStack.Pod import Pod 24 | from ZenPacks.zenoss.CloudStack.SystemVM import SystemVM 25 | from ZenPacks.zenoss.CloudStack.RouterVM import RouterVM 26 | from ZenPacks.zenoss.CloudStack.Cluster import Cluster 27 | from ZenPacks.zenoss.CloudStack.Host import Host 28 | from ZenPacks.zenoss.CloudStack.VirtualMachine import VirtualMachine 29 | 30 | 31 | ### IRelatable Adapters 32 | 33 | class CloudRelatable(BaseRelatable): 34 | adapts(Cloud) 35 | 36 | group = 'CloudStack' 37 | 38 | 39 | class ZoneRelatable(DeviceComponentRelatable): 40 | adapts(Zone) 41 | 42 | group = 'CloudStack' 43 | 44 | 45 | class PodRelatable(DeviceComponentRelatable): 46 | adapts(Pod) 47 | 48 | group = 'CloudStack' 49 | 50 | 51 | class SystemVMRelatable(DeviceComponentRelatable): 52 | adapts(SystemVM) 53 | 54 | group = 'CloudStack' 55 | 56 | 57 | class RouterVMRelatable(DeviceComponentRelatable): 58 | adapts(RouterVM) 59 | 60 | group = 'CloudStack' 61 | 62 | 63 | class ClusterRelatable(DeviceComponentRelatable): 64 | adapts(Cluster) 65 | 66 | group = 'CloudStack' 67 | 68 | 69 | class HostRelatable(DeviceComponentRelatable): 70 | adapts(Host) 71 | 72 | group = 'CloudStack' 73 | 74 | 75 | class VirtualMachineRelatable(DeviceComponentRelatable): 76 | adapts(VirtualMachine) 77 | 78 | group = 'CloudStack' 79 | 80 | 81 | ### IRelationsProvider Adapters 82 | 83 | class CloudRelationsProvider(BaseRelationsProvider): 84 | adapts(Cloud) 85 | 86 | def relations(self, type=TAG_ALL): 87 | if type in (TAG_ALL, TAG_IMPACTS): 88 | for zone in self._adapted.zones(): 89 | yield self.constructRelationTo(zone, TAG_IMPACTS) 90 | 91 | 92 | class ZoneRelationsProvider(BaseRelationsProvider): 93 | adapts(Zone) 94 | 95 | def relations(self, type=TAG_ALL): 96 | if type in (TAG_ALL, TAG_IMPACTS): 97 | for pod in self._adapted.pods(): 98 | yield self.constructRelationTo(pod, TAG_IMPACTS) 99 | 100 | if type in (TAG_ALL, TAG_IMPACTED_BY): 101 | yield self.constructRelationTo( 102 | self._adapted.cloud(), TAG_IMPACTED_BY) 103 | 104 | 105 | class PodRelationsProvider(BaseRelationsProvider): 106 | adapts(Pod) 107 | 108 | def relations(self, type=TAG_ALL): 109 | if type in (TAG_ALL, TAG_IMPACTS): 110 | for cluster in self._adapted.clusters(): 111 | yield self.constructRelationTo(cluster, TAG_IMPACTS) 112 | 113 | if type in (TAG_ALL, TAG_IMPACTED_BY): 114 | yield self.constructRelationTo( 115 | self._adapted.zone(), TAG_IMPACTED_BY) 116 | 117 | 118 | class SystemVMRelationsProvider(BaseRelationsProvider): 119 | adapts(SystemVM) 120 | 121 | def relations(self, type=TAG_ALL): 122 | if type in (TAG_ALL, TAG_IMPACTS): 123 | yield self.constructRelationTo(self._adapted.pod(), TAG_IMPACTS) 124 | 125 | if type in (TAG_ALL, TAG_IMPACTED_BY): 126 | host = self._adapted.host() 127 | if host: 128 | yield self.constructRelationTo(host, TAG_IMPACTED_BY) 129 | 130 | 131 | class RouterVMRelationsProvider(BaseRelationsProvider): 132 | adapts(RouterVM) 133 | 134 | def relations(self, type=TAG_ALL): 135 | if type in (TAG_ALL, TAG_IMPACTED_BY): 136 | host = self._adapted.host() 137 | if host: 138 | yield self.constructRelationTo(host, TAG_IMPACTED_BY) 139 | 140 | 141 | class ClusterRelationsProvider(BaseRelationsProvider): 142 | adapts(Cluster) 143 | 144 | def relations(self, type=TAG_ALL): 145 | if type in (TAG_ALL, TAG_IMPACTS): 146 | for host in self._adapted.hosts(): 147 | yield self.constructRelationTo(host, TAG_IMPACTS) 148 | 149 | if type in (TAG_ALL, TAG_IMPACTED_BY): 150 | yield self.constructRelationTo( 151 | self._adapted.pod(), TAG_IMPACTED_BY) 152 | 153 | 154 | class HostRelationsProvider(BaseRelationsProvider): 155 | adapts(Host) 156 | 157 | def relations(self, type=TAG_ALL): 158 | if type in (TAG_ALL, TAG_IMPACTS): 159 | for systemvm in self._adapted.systemvms(): 160 | yield self.constructRelationTo(systemvm, TAG_IMPACTS) 161 | 162 | for routervm in self._adapted.routervms(): 163 | yield self.constructRelationTo(routervm, TAG_IMPACTS) 164 | 165 | for vm in self._adapted.vms(): 166 | yield self.constructRelationTo(vm, TAG_IMPACTS) 167 | 168 | if type in (TAG_ALL, TAG_IMPACTED_BY): 169 | yield self.constructRelationTo(self._adapted.cluster()) 170 | 171 | device = self._adapted.getManagedDevice() 172 | if device: 173 | yield self.constructRelationTo(device, TAG_IMPACTED_BY) 174 | 175 | 176 | class VirtualMachineRelationsProvider(BaseRelationsProvider): 177 | adapts(VirtualMachine) 178 | 179 | def relations(self, type=TAG_ALL): 180 | if type in (TAG_ALL, TAG_IMPACTS): 181 | device = self._adapted.getManagedDevice() 182 | if device: 183 | self.constructRelationTo(device, TAG_IMPACTS) 184 | 185 | if type in (TAG_ALL, TAG_IMPACTED_BY): 186 | yield self.constructRelationTo( 187 | self._adapted.zone(), TAG_IMPACTED_BY) 188 | 189 | host = self._adapted.getManagedDevice() 190 | if host: 191 | self.constructRelationTo(host, TAG_IMPACTED_BY) 192 | -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/dynamicview/configure.zcml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 16 | 17 | 22 | 23 | 28 | 29 | 34 | 35 | 40 | 41 | 46 | 47 | 52 | 53 | 54 | 55 | 60 | 61 | 66 | 67 | 72 | 73 | 78 | 79 | 84 | 85 | 90 | 91 | 96 | 97 | 102 | 103 | 104 | 105 | 106 | 107 | 113 | 114 | 119 | 120 | 125 | 126 | 131 | 132 | 133 | -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/facades.py: -------------------------------------------------------------------------------- 1 | ########################################################################### 2 | # 3 | # This program is part of Zenoss Core, an open source monitoring platform. 4 | # Copyright (C) 2011, Zenoss Inc. 5 | # 6 | # This program is free software; you can redistribute it and/or modify it 7 | # under the terms of the GNU General Public License version 2 or (at your 8 | # option) any later version as published by the Free Software Foundation. 9 | # 10 | # For complete information please visit: http://www.zenoss.com/oss/ 11 | # 12 | ########################################################################### 13 | 14 | from urlparse import urlparse 15 | 16 | from zope.interface import implements 17 | from zope.event import notify 18 | from ZODB.transact import transact 19 | 20 | from Products.Zuul.catalog.events import IndexingEvent 21 | from Products.Zuul.facades import ZuulFacade 22 | from Products.Zuul.utils import ZuulMessageFactory as _t 23 | 24 | from ZenPacks.zenoss.CloudStack.interfaces import ICloudStackFacade 25 | 26 | 27 | class CloudStackFacade(ZuulFacade): 28 | implements(ICloudStackFacade) 29 | 30 | def add_cloudstack(self, device_name, url, api_key, secret_key, collector='localhost'): 31 | """Handles adding a new CloudStack cloud to the system.""" 32 | 33 | @transact 34 | def create_device(): 35 | dc = self._dmd.Devices.getOrganizer('/Devices/CloudStack') 36 | 37 | account = dc.createInstance(device_name) 38 | account.setPerformanceMonitor(collector) 39 | account.setZenProperty('zCloudStackURL', url) 40 | account.setZenProperty('zCloudStackAPIKey', api_key) 41 | account.setZenProperty('zCloudStackSecretKey', secret_key) 42 | 43 | account.index_object() 44 | notify(IndexingEvent(account)) 45 | 46 | 47 | deviceRoot = self._dmd.getDmdRoot("Devices") 48 | device = deviceRoot.findDeviceByIdExact(device_name) 49 | if device: 50 | return False, _t("A device named %s already exists." % device_name) 51 | 52 | # This must be committed before the following model can be 53 | # scheduled. 54 | create_device() 55 | 56 | # Schedule a modeling job for the new account. 57 | account = deviceRoot.findDeviceByIdExact(device_name) 58 | account.collectDevice(setlog=False, background=True) 59 | 60 | return True 61 | -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/impact.py: -------------------------------------------------------------------------------- 1 | ############################################################################## 2 | # 3 | # Copyright (C) Zenoss, Inc. 2013, all rights reserved. 4 | # 5 | # This content is made available according to terms specified in 6 | # License.zenoss under the directory where your Zenoss product is installed. 7 | # 8 | ############################################################################## 9 | 10 | from ZenPacks.zenoss.CloudStack import ZENPACK_NAME 11 | from ZenPacks.zenoss.CloudStack.utils import guid 12 | 13 | # Lazy imports to make this module not require Impact. 14 | ImpactEdge = None 15 | Trigger = None 16 | 17 | # Constants to avoid typos. 18 | AVAILABILITY = 'AVAILABILITY' 19 | PERCENT = 'policyPercentageTrigger' 20 | THRESHOLD = 'policyThresholdTrigger' 21 | DOWN = 'DOWN' 22 | DEGRADED = 'DEGRADED' 23 | ATRISK = 'ATRISK' 24 | 25 | 26 | def edge(source, target): 27 | ''' 28 | Create an edge indicating that source impacts target. 29 | 30 | source and target are expected to be GUIDs. 31 | ''' 32 | # Lazy import without incurring import overhead. 33 | # http://wiki.python.org/moin/PythonSpeed/PerformanceTips#Import_Statement_Overhead 34 | global ImpactEdge 35 | if not ImpactEdge: 36 | from ZenPacks.zenoss.Impact.impactd.relations import ImpactEdge 37 | 38 | return ImpactEdge(source, target, ZENPACK_NAME) 39 | 40 | 41 | class BaseImpactAdapterFactory(object): 42 | ''' 43 | Abstract base for Impact adapter factories. 44 | ''' 45 | 46 | def __init__(self, adapted): 47 | self.adapted = adapted 48 | 49 | def guid(self): 50 | if not hasattr(self, '_guid'): 51 | self._guid = guid(self.adapted) 52 | 53 | return self._guid 54 | 55 | 56 | class BaseRelationsProvider(BaseImpactAdapterFactory): 57 | ''' 58 | Abstract base for IRelationshipDataProvider adapter factories. 59 | ''' 60 | 61 | relationship_provider = ZENPACK_NAME 62 | 63 | impact_relationships = None 64 | impacted_by_relationships = None 65 | 66 | def belongsInImpactGraph(self): 67 | return True 68 | 69 | def impact(self, relname): 70 | relationship = getattr(self.adapted, relname, None) 71 | if relationship and callable(relationship): 72 | related = relationship() 73 | if not related: 74 | return 75 | 76 | try: 77 | for obj in related: 78 | yield edge(self.guid(), guid(obj)) 79 | 80 | except TypeError: 81 | yield edge(self.guid(), guid(related)) 82 | 83 | def impacted_by(self, relname): 84 | relationship = getattr(self.adapted, relname, None) 85 | if relationship and callable(relationship): 86 | related = relationship() 87 | if not related: 88 | return 89 | 90 | try: 91 | for obj in related: 92 | yield edge(guid(obj), self.guid()) 93 | 94 | except TypeError: 95 | yield edge(guid(related), self.guid()) 96 | 97 | def getEdges(self): 98 | if self.impact_relationships is not None: 99 | for impact_relationship in self.impact_relationships: 100 | for impact in self.impact(impact_relationship): 101 | yield impact 102 | 103 | if self.impacted_by_relationships is not None: 104 | for impacted_by_relationship in self.impacted_by_relationships: 105 | for impacted_by in self.impacted_by(impacted_by_relationship): 106 | yield impacted_by 107 | 108 | 109 | class BaseTriggers(BaseImpactAdapterFactory): 110 | ''' 111 | Abstract base for INodeTriggers adapter factories. 112 | ''' 113 | triggers = [] 114 | 115 | def get_triggers(self): 116 | ''' 117 | Return list of triggers defined by subclass' triggers property. 118 | ''' 119 | # Lazy import without incurring import overhead. 120 | # http://wiki.python.org/moin/PythonSpeed/PerformanceTips#Import_Statement_Overhead 121 | global Trigger 122 | if not Trigger: 123 | from ZenPacks.zenoss.Impact.impactd import Trigger 124 | 125 | for trigger_args in self.triggers: 126 | yield Trigger(self.guid(), *trigger_args) 127 | 128 | 129 | ### CloudStack Impact Providers ############################################## 130 | 131 | class HostRelationsProvider(BaseRelationsProvider): 132 | impacted_by_relationships = ('xenserver_host',) 133 | 134 | 135 | class RouterVMRelationsProvider(BaseRelationsProvider): 136 | impacted_by_relationships = ('xenserver_vm',) 137 | 138 | 139 | class SystemVMRelationsProvider(BaseRelationsProvider): 140 | impacted_by_relationships = ('xenserver_vm',) 141 | 142 | 143 | class VirtualMachineRelationsProvider(BaseRelationsProvider): 144 | impacted_by_relationships = ('xenserver_vm',) 145 | -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/info.py: -------------------------------------------------------------------------------- 1 | ########################################################################### 2 | # 3 | # This program is part of Zenoss Core, an open source monitoring platform. 4 | # Copyright (C) 2011, 2012 Zenoss Inc. 5 | # 6 | # This program is free software; you can redistribute it and/or modify it 7 | # under the terms of the GNU General Public License version 2 or (at your 8 | # option) any later version as published by the Free Software Foundation. 9 | # 10 | # For complete information please visit: http://www.zenoss.com/oss/ 11 | # 12 | ########################################################################### 13 | 14 | from zope.interface import implements 15 | 16 | from Products.Zuul.decorators import info 17 | from Products.Zuul.infos import ProxyProperty 18 | from Products.Zuul.infos.device import DeviceInfo 19 | from Products.Zuul.infos.component import ComponentInfo 20 | 21 | from ZenPacks.zenoss.CloudStack.interfaces import ( 22 | ICloudInfo, IZoneInfo, IPodInfo, ISystemVMInfo, IRouterVMInfo, 23 | IClusterInfo, IHostInfo, IVirtualMachineInfo) 24 | 25 | 26 | class CloudInfo(DeviceInfo): 27 | """Cloud API (Info) adapter factory.""" 28 | 29 | implements(ICloudInfo) 30 | 31 | @property 32 | def zone_count(self): 33 | return self._object.zones.countObjects() 34 | 35 | @property 36 | def pod_count(self): 37 | return reduce( 38 | lambda x, y: x + y.pods.countObjects(), 39 | self._object.zones(), 40 | 0) 41 | 42 | @property 43 | def cluster_count(self): 44 | count = 0 45 | for zone in self._object.zones(): 46 | for pod in zone.pods(): 47 | count += pod.clusters.countObjects() 48 | 49 | return count 50 | 51 | @property 52 | def host_count(self): 53 | count = 0 54 | for zone in self._object.zones(): 55 | for pod in zone.pods(): 56 | for cluster in pod.clusters(): 57 | count += cluster.hosts.countObjects() 58 | 59 | return count 60 | 61 | 62 | class BaseComponentInfo(ComponentInfo): 63 | """Abstract base component API (Info) adapter factory.""" 64 | 65 | cloudstack_id = ProxyProperty('cloudstack_id') 66 | allocation_state = ProxyProperty('allocation_state') 67 | 68 | @property 69 | def icon(self): 70 | return self._object.getIconPath() 71 | 72 | 73 | class ZoneInfo(BaseComponentInfo): 74 | """Zone API (Info) adapter factory.""" 75 | 76 | implements(IZoneInfo) 77 | 78 | guest_cidr_address = ProxyProperty('guest_cidr_address') 79 | dhcp_provider = ProxyProperty('dhcp_provider') 80 | network_type = ProxyProperty('network_type') 81 | security_groups_enabled = ProxyProperty('security_groups_enabled') 82 | vlan = ProxyProperty('vlan') 83 | zone_token = ProxyProperty('zone_token') 84 | 85 | @property 86 | def public_dns(self): 87 | return ', '.join((self._object.dns1, self._object.dns2)) 88 | 89 | @property 90 | def internal_dns(self): 91 | return ', '.join(( 92 | self._object.internal_dns1, self._object.internal_dns1)) 93 | 94 | @property 95 | def pod_count(self): 96 | return self._object.pods.countObjects() 97 | 98 | @property 99 | def cluster_count(self): 100 | return reduce( 101 | lambda x, y: x + y.clusters.countObjects(), 102 | self._object.pods(), 103 | 0) 104 | 105 | @property 106 | def host_count(self): 107 | count = 0 108 | for pod in self._object.pods(): 109 | for cluster in pod.clusters(): 110 | count += cluster.hosts.countObjects() 111 | 112 | return count 113 | 114 | 115 | class PodInfo(BaseComponentInfo): 116 | """Pod API (Info) adapter factory.""" 117 | 118 | implements(IPodInfo) 119 | 120 | netmask = ProxyProperty('netmask') 121 | gateway = ProxyProperty('gateway') 122 | 123 | @property 124 | def ip_range(self): 125 | return "%s - %s" % (self._object.start_ip, self._object.end_ip) 126 | 127 | @property 128 | @info 129 | def zone(self): 130 | return self._object.zone() 131 | 132 | @property 133 | def cluster_count(self): 134 | return self._object.clusters.countObjects() 135 | 136 | @property 137 | def host_count(self): 138 | return reduce( 139 | lambda x, y: x + y.hosts.countObjects(), 140 | self._object.clusters(), 141 | 0) 142 | 143 | 144 | class SystemVMInfo(BaseComponentInfo): 145 | """SystemVM API (Info) adapter factory.""" 146 | 147 | implements(ISystemVMInfo) 148 | 149 | systemvm_type = ProxyProperty('systemvm_type') 150 | network_domain = ProxyProperty('network_domain') 151 | gateway = ProxyProperty('gateway') 152 | public_ip = ProxyProperty('public_ip') 153 | public_netmask = ProxyProperty('public_netmask') 154 | public_macaddress = ProxyProperty('public_macaddress') 155 | private_ip = ProxyProperty('private_ip') 156 | private_netmask = ProxyProperty('private_netmask') 157 | private_macaddress = ProxyProperty('private_macaddress') 158 | linklocal_ip = ProxyProperty('linklocal_ip') 159 | linklocal_netmask = ProxyProperty('linklocal_netmask') 160 | linklocal_macaddress = ProxyProperty('linklocal_macaddress') 161 | template_id = ProxyProperty('template_id') 162 | 163 | @property 164 | @info 165 | def zone(self): 166 | return self._object.pod().zone() 167 | 168 | @property 169 | @info 170 | def pod(self): 171 | return self._object.pod() 172 | 173 | @property 174 | @info 175 | def host(self): 176 | return self._object.host() 177 | 178 | 179 | class RouterVMInfo(BaseComponentInfo): 180 | """RouterVM API (Info) adapter factory.""" 181 | 182 | implements(IRouterVMInfo) 183 | 184 | account = ProxyProperty('account') 185 | created = ProxyProperty('created') 186 | dns1 = ProxyProperty('dns1') 187 | dns2 = ProxyProperty('dns2') 188 | domain = ProxyProperty('domain') 189 | gateway = ProxyProperty('gateway') 190 | guest_ip = ProxyProperty('guest_ip') 191 | guest_netmask = ProxyProperty('guest_netmask') 192 | guest_macaddress = ProxyProperty('guest_macaddress') 193 | linklocal_ip = ProxyProperty('linklocal_ip') 194 | linklocal_netmask = ProxyProperty('linklocal_netmask') 195 | linklocal_macaddress = ProxyProperty('linklocal_macaddress') 196 | network_domain = ProxyProperty('network_domain') 197 | public_ip = ProxyProperty('public_ip') 198 | public_netmask = ProxyProperty('public_netmask') 199 | public_macaddress = ProxyProperty('public_macaddress') 200 | state = ProxyProperty('state') 201 | template_id = ProxyProperty('template_id') 202 | 203 | @property 204 | @info 205 | def zone(self): 206 | return self._object.pod().zone() 207 | 208 | @property 209 | @info 210 | def pod(self): 211 | return self._object.pod() 212 | 213 | @property 214 | @info 215 | def host(self): 216 | return self._object.host() 217 | 218 | 219 | class ClusterInfo(BaseComponentInfo): 220 | """Cluster API (Info) adapter factory.""" 221 | 222 | implements(IClusterInfo) 223 | 224 | cluster_type = ProxyProperty('cluster_type') 225 | hypervisor_type = ProxyProperty('hypervisor_type') 226 | managed_state = ProxyProperty('managed_state') 227 | 228 | @property 229 | @info 230 | def zone(self): 231 | return self._object.pod().zone() 232 | 233 | @property 234 | @info 235 | def pod(self): 236 | return self._object.pod() 237 | 238 | @property 239 | def host_count(self): 240 | return self._object.hosts.countObjects() 241 | 242 | 243 | class HostInfo(BaseComponentInfo): 244 | """Host API (Info) adapter factory.""" 245 | 246 | implements(IHostInfo) 247 | 248 | host_type = ProxyProperty('host_type') 249 | hypervisor = ProxyProperty('hypervisor') 250 | host_version = ProxyProperty('host_version') 251 | capabilities = ProxyProperty('capabilities') 252 | host_state = ProxyProperty('host_state') 253 | created = ProxyProperty('created') 254 | host_tags = ProxyProperty('host_tags') 255 | ip_address = ProxyProperty('ip_address') 256 | host_events = ProxyProperty('host_events') 257 | local_storage_active = ProxyProperty('local_storage_active') 258 | management_server_id = ProxyProperty('management_server_id') 259 | 260 | @property 261 | @info 262 | def zone(self): 263 | return self._object.cluster().pod().zone() 264 | 265 | @property 266 | @info 267 | def pod(self): 268 | return self._object.cluster().pod() 269 | 270 | @property 271 | @info 272 | def cluster(self): 273 | return self._object.cluster() 274 | 275 | @property 276 | @info 277 | def managed_device(self): 278 | return self._object.getManagedDevice() 279 | 280 | 281 | class VirtualMachineInfo(BaseComponentInfo): 282 | """VirtualMachine API (Info) adapter factory.""" 283 | 284 | implements(IVirtualMachineInfo) 285 | 286 | account = ProxyProperty('account') 287 | cpu_number = ProxyProperty('cpu_number') 288 | cpu_speed = ProxyProperty('cpu_speed') 289 | created = ProxyProperty('created') 290 | display_name = ProxyProperty('display_name') 291 | domain = ProxyProperty('domain') 292 | ha_enable = ProxyProperty('ha_enable') 293 | memory = ProxyProperty('memory') 294 | mac_address = ProxyProperty('mac_address') 295 | ip_address = ProxyProperty('ip_address') 296 | netmask = ProxyProperty('netmask') 297 | gateway = ProxyProperty('gateway') 298 | root_device_type = ProxyProperty('root_device_type') 299 | service_offering = ProxyProperty('service_offering') 300 | state = ProxyProperty('state') 301 | template = ProxyProperty('template') 302 | 303 | @property 304 | @info 305 | def zone(self): 306 | return self._object.zone() 307 | 308 | @property 309 | @info 310 | def host(self): 311 | return self._object.host() 312 | 313 | @property 314 | @info 315 | def managed_device(self): 316 | return self._object.getManagedDevice() 317 | -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/interfaces.py: -------------------------------------------------------------------------------- 1 | ########################################################################### 2 | # 3 | # This program is part of Zenoss Core, an open source monitoring platform. 4 | # Copyright (C) 2011, 2012 Zenoss Inc. 5 | # 6 | # This program is free software; you can redistribute it and/or modify it 7 | # under the terms of the GNU General Public License version 2 or (at your 8 | # option) any later version as published by the Free Software Foundation. 9 | # 10 | # For complete information please visit: http://www.zenoss.com/oss/ 11 | # 12 | ########################################################################### 13 | 14 | from Products.Zuul.form import schema 15 | from Products.Zuul.interfaces import IFacade 16 | from Products.Zuul.interfaces import IDeviceInfo 17 | from Products.Zuul.interfaces.component import IComponentInfo 18 | from Products.Zuul.utils import ZuulMessageFactory as _t 19 | 20 | # In Zenoss 3 we mistakenly mapped TextLine to Zope's multi-line text 21 | # equivalent and Text to Zope's single-line text equivalent. This was 22 | # backwards so we flipped their meanings in Zenoss 4. The following block of 23 | # code allows the ZenPack to work properly in Zenoss 3 and 4. 24 | 25 | # Until backwards compatibility with Zenoss 3 is no longer desired for your 26 | # ZenPack it is recommended that you use "SingleLineText" and "MultiLineText" 27 | # instead of schema.TextLine or schema.Text. 28 | from Products.ZenModel.ZVersion import VERSION as ZENOSS_VERSION 29 | from Products.ZenUtils.Version import Version 30 | 31 | # One of the following branches below will not be covered by unit tests on any 32 | # given Zenoss version because it is a Zenoss version test. 33 | if Version.parse('Zenoss %s' % ZENOSS_VERSION) >= Version.parse('Zenoss 4'): 34 | SingleLineText = schema.TextLine 35 | MultiLineText = schema.Text 36 | else: 37 | SingleLineText = schema.Text 38 | MultiLineText = schema.TextLine 39 | 40 | 41 | class ICloudStackFacade(IFacade): 42 | def add_cloudstack(self, url, api_key, secret_key): 43 | """Add CloudStack cloud.""" 44 | 45 | 46 | class ICloudInfo(IDeviceInfo): 47 | """Interface for Cloud API (Info) adapter.""" 48 | 49 | zone_count = schema.Int(title=_t(u"Zone Count")) 50 | pod_count = schema.Int(title=_t(u"Pod Count")) 51 | cluster_count = schema.Int(title=_t(u"Cluster Count")) 52 | host_count = schema.Int(title=_t(u"Host Count")) 53 | 54 | 55 | class IBaseComponentInfo(IComponentInfo): 56 | """Abstract base component API (Info) adapter.""" 57 | 58 | cloudstack_id = schema.Int(title=_t(u"CloudStack ID")) 59 | allocation_state = SingleLineText(title=_t(u"Allocation State")) 60 | 61 | 62 | class IZoneInfo(IBaseComponentInfo): 63 | """Interface for Zone API (Info) adapter.""" 64 | 65 | guest_cidr_address = SingleLineText(title=_t(u"Guest CIDR Address")) 66 | dhcp_provider = SingleLineText(title=_t(u"DHCP Provider")) 67 | public_dns = SingleLineText(title=_t(u"Public DNS")) 68 | internal_dns = SingleLineText(title=_t(u"Internal DNS")) 69 | network_type = SingleLineText(title=_t(u"Network Type")) 70 | security_groups_enabled = schema.Bool(title=_t(u"Security Groups Enabled")) 71 | vlan = SingleLineText(title=_t(u"VLAN Range")) 72 | zone_token = SingleLineText(title=_t(u"Zone Token")) 73 | pod_count = schema.Int(title=_t(u"Pod Count")) 74 | cluster_count = schema.Int(title=_t(u"Cluster Count")) 75 | host_count = schema.Int(title=_t(u"Host Count")) 76 | 77 | 78 | class IPodInfo(IBaseComponentInfo): 79 | """Interface for Pod API (Info) adapter.""" 80 | 81 | ip_range = SingleLineText(title=_t(u"IP Range")) 82 | netmask = SingleLineText(title=_t(u"Netmask")) 83 | gateway = SingleLineText(title=_t(u"Gateway")) 84 | zone = schema.Entity(title=_t(u"Zone")) 85 | cluster_count = schema.Int(title=_t(u"Cluster Count")) 86 | host_count = schema.Int(title=_t(u"Host Count")) 87 | 88 | 89 | class ISystemVMInfo(IBaseComponentInfo): 90 | """Interface for SystemVM API (Info) adapter.""" 91 | 92 | systemvm_type = SingleLineText(title=_t(u"System VM Type")) 93 | host = schema.Entity(title=_t(u"Host")) 94 | network_domain = SingleLineText(title=_t(u"Network Domain")) 95 | gateway = SingleLineText(title=_t(u"Gateway")) 96 | public_ip = SingleLineText(title=_t(u"Public IP Address")) 97 | public_netmask = SingleLineText(title=_t(u"Public Netmask")) 98 | public_macaddress = SingleLineText(title=_t(u"Public MAC Address")) 99 | private_ip = SingleLineText(title=_t(u"Private IP Address")) 100 | private_netmask = SingleLineText(title=_t(u"Private Netmask")) 101 | private_macaddress = SingleLineText(title=_t(u"Private MAC Addresss")) 102 | linklocal_ip = SingleLineText(title=_t(u"Link-local IP Address")) 103 | linklocal_netmask = SingleLineText(title=_t(u"Link-local Netmask")) 104 | linklocal_macaddress = SingleLineText(title=_t(u"Link-local MAC Address")) 105 | template_id = schema.Int(title=_t(u"Template ID")) 106 | 107 | 108 | class IRouterVMInfo(IBaseComponentInfo): 109 | """Interface for RouterVM API (Info) adapter.""" 110 | 111 | account = SingleLineText(title=_t(u"Account")) 112 | created = SingleLineText(title=_t(u"Created")) 113 | dns1 = SingleLineText(title=_t(u"Primary DNS")) 114 | dns2 = SingleLineText(title=_t(u"Secondary DNS")) 115 | domain = SingleLineText(title=_t(u"Domain")) 116 | gateway = SingleLineText(title=_t(u"Gateway")) 117 | guest_ip = SingleLineText(title=_t(u"Guest IP Address")) 118 | guest_netmask = SingleLineText(title=_t(u"Guest Netmask")) 119 | guest_macaddress = SingleLineText(title=_t(u"Guest MAC Addresss")) 120 | host = schema.Entity(title=_t(u"Host")) 121 | linklocal_ip = SingleLineText(title=_t(u"Link-local IP Address")) 122 | linklocal_netmask = SingleLineText(title=_t(u"Link-local Netmask")) 123 | linklocal_macaddress = SingleLineText(title=_t(u"Link-local MAC Address")) 124 | network_domain = SingleLineText(title=_t(u"Network Domain")) 125 | public_ip = SingleLineText(title=_t(u"Public IP Address")) 126 | public_netmask = SingleLineText(title=_t(u"Public Netmask")) 127 | public_macaddress = SingleLineText(title=_t(u"Public MAC Address")) 128 | state = SingleLineText(title=_t(u"State")) 129 | template_id = schema.Int(title=_t(u"Template ID")) 130 | 131 | 132 | class IClusterInfo(IBaseComponentInfo): 133 | """Interface for Cluster API (Info) adapter.""" 134 | 135 | cluster_type = SingleLineText(title=_t(u"Cluster Type")) 136 | hypervisor_type = SingleLineText(title=_t(u"Hypervisor Type")) 137 | managed_state = SingleLineText(title=_t(u"Managed State")) 138 | zone = schema.Entity(title=_t(u"Zone")) 139 | pod = schema.Entity(title=_t(u"Pod")) 140 | host_count = schema.Int(title=_t(u"Host Count")) 141 | 142 | 143 | class IHostInfo(IBaseComponentInfo): 144 | """Interface for Host API (Info) adapter.""" 145 | 146 | host_type = SingleLineText(title=_t(u"Host Type")) 147 | hypervisor = SingleLineText(title=_t(u"Hypervisor")) 148 | host_version = SingleLineText(title=_t(u"Version")) 149 | capabilities = SingleLineText(title=_t(u"Capabilities")) 150 | host_state = SingleLineText(title=_t(u"Host State")) 151 | created = SingleLineText(title=_t(u"Created")) 152 | host_tags = SingleLineText(title=_t(u"Host Tags")) 153 | ip_address = SingleLineText(title=_t(u"IP Address")) 154 | host_events = SingleLineText(title=_t(u"Event Types")) 155 | local_storage_active = schema.Bool(title=_t(u"Local Storage Active")) 156 | management_server_id = schema.Int(title=_t(u"Management Server Identifier")) 157 | zone = schema.Entity(title=_t(u"Zone")) 158 | pod = schema.Entity(title=_t(u"Pod")) 159 | cluster = schema.Entity(title=_t(u"Cluster")) 160 | managed_device = schema.Entity(title=_t(u"Managed Device")) 161 | 162 | 163 | class IVirtualMachineInfo(IBaseComponentInfo): 164 | """Interface for VirtualMachine API (Info) adapter.""" 165 | 166 | account = SingleLineText(title=_t(u"Account")) 167 | cpu_number = schema.Int(title=_t(u"Number of CPUs")) 168 | cpu_speed = schema.Int(title=_t(u"CPU Speed")) 169 | created = SingleLineText(title=_t(u"Created")) 170 | display_name = SingleLineText(title=_t(u"Display Name")) 171 | domain = SingleLineText(title=_t(u"Domain")) 172 | ha_enable = schema.Bool(title=_t(u"HA Enabled")) 173 | host = schema.Entity(title=_t(u"Host")) 174 | memory = schema.Int(title=_t(u"Memory")) 175 | mac_address = SingleLineText(title=_t(u"MAC Address")) 176 | ip_address = SingleLineText(title=_t(u"IP Address")) 177 | netmask = SingleLineText(title=_t(u"Netmask")) 178 | gateway = SingleLineText(title=_t(u"Gateway")) 179 | root_device_type = SingleLineText(title=_t(u"Root Device Type")) 180 | service_offering = SingleLineText(title=_t(u"Service Offering")) 181 | state = SingleLineText(title=_t(u"State")) 182 | template = SingleLineText(title=_t(u"Template")) 183 | managed_device = schema.Entity(title=_t(u"Managed Device")) 184 | -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/lib/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenoss/ZenPacks.zenoss.CloudStack/a3156e7f13f3cd04a4cbc588c3d36d036b696a34/ZenPacks/zenoss/CloudStack/lib/__init__.py -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/lib/txcloudstack.py: -------------------------------------------------------------------------------- 1 | ########################################################################### 2 | # 3 | # This program is part of Zenoss Core, an open source monitoring platform. 4 | # Copyright (C) 2011, 2012 Zenoss Inc. 5 | # 6 | # This program is free software; you can redistribute it and/or modify it 7 | # under the terms of the GNU General Public License version 2 or (at your 8 | # option) any later version as published by the Free Software Foundation. 9 | # 10 | # For complete information please visit: http://www.zenoss.com/oss/ 11 | # 12 | ########################################################################### 13 | 14 | import base64 15 | import hashlib 16 | import hmac 17 | import json 18 | import urllib 19 | 20 | from twisted.internet import defer 21 | import twisted.web.client 22 | 23 | 24 | __all__ = ['Client', 'capacity_type_string'] 25 | 26 | 27 | def capacity_type_string(type_id): 28 | """Return a string representation for the given capacity type_id. 29 | 30 | This list comes from the following URL: 31 | http://cloudstack.org/forum/6-general-discussion/7102-performance-monitoring-option-for-cloudcom.html 32 | """ 33 | return { 34 | 0: 'memory', # bytes 35 | 1: 'cpu', # MHz 36 | 2: 'primary_storage_used', # bytes 37 | 3: 'primary_storage_allocated', # bytes 38 | 4: 'public_ips', 39 | 5: 'private_ips', 40 | 6: 'secondary_storage', # bytes 41 | }.get(type_id, 'unknown') 42 | 43 | 44 | class Client(object): 45 | """CloudStack client.""" 46 | 47 | def __init__(self, base_url, api_key, secret_key): 48 | self.base_url = base_url.rstrip('/') 49 | self.api_key = api_key 50 | self.secret_key = secret_key 51 | self._page_size = None 52 | 53 | def _sign(self, url): 54 | """Generate a signed URL for the provided url and secret key. 55 | 56 | The procedure for creating a signature is documented at 57 | http://docs.cloud.com/CloudStack_Documentation/Developer's_Guide%3A_CloudStack 58 | """ 59 | 60 | base_url, query_string = url.split('?') 61 | msg = '&'.join(sorted(x.lower() for x in query_string.split('&'))) 62 | 63 | signature = base64.b64encode(hmac.new( 64 | self.secret_key, msg=msg, digestmod=hashlib.sha1).digest()) 65 | 66 | return '%s?%s&signature=%s' % ( 67 | base_url, query_string, urllib.quote(signature)) 68 | 69 | def _request_single(self, command, **kwargs): 70 | def process_result(result): 71 | data = json.loads(result) 72 | 73 | # For generating test data. 74 | # f = open('%s.json' % data.keys()[0], 'wb') 75 | # f.write(result) 76 | # f.close() 77 | 78 | return data 79 | 80 | params = kwargs 81 | params['command'] = command 82 | params['apiKey'] = self.api_key 83 | params['response'] = 'json' 84 | 85 | url = self._sign("%s/client/api?%s" % ( 86 | self.base_url, urllib.urlencode(params))) 87 | 88 | return twisted.web.client.getPage(url).addCallback(process_result) 89 | 90 | def _get_page_size(self): 91 | # use listEvents to get pagesize, since every user can call it 92 | # but listEvents normally would not produce pagesize except in 93 | # error message 94 | # the use of 1000000 is intentional in order to generate error 95 | # and therefore, addErrback() 96 | if self._page_size is None: 97 | d = self._request_single( 98 | 'listEvents', page=1, pagesize=1000000) 99 | 100 | return d.addErrback(self._process_page_size_error) 101 | else: 102 | return defer.succeed() 103 | 104 | def _process_page_size_error(self, result): 105 | if hasattr(result, 'value') and hasattr(result.value, 'response'): 106 | response = json.loads(result.value.response) 107 | listEventResponse = response.get('listeventsresponse', None) 108 | if listEventResponse: 109 | errorText = listEventResponse.get('errortext', None) 110 | if errorText and ':' in errorText: 111 | self._page_size = int(errorText[errorText.index(':') + 1:].strip()) 112 | 113 | def _request_page(self, result, page, all_results, command, **kwargs): 114 | response_key = '%sresponse' % command.lower() 115 | 116 | # Need to get first page. 117 | if result is None: 118 | d = self._request_single( 119 | command, page=page, pagesize=self._page_size, **kwargs) 120 | 121 | d.addCallback( 122 | self._request_page, page, all_results, command, **kwargs) 123 | 124 | return d 125 | 126 | # Already have at least one page. Combine and decide if we need another. 127 | else: 128 | all_results.setdefault(response_key, {}) 129 | 130 | for k, v in result[response_key].items(): 131 | if k in all_results[response_key]: 132 | if k == 'count': 133 | all_results[response_key][k] += v 134 | else: 135 | all_results[response_key][k].extend(v) 136 | else: 137 | all_results[response_key][k] = v 138 | 139 | # Internal hard limit of 20 pages. At this many pages responses 140 | # take too long to be useful. More data can be captured by 141 | # increasing CloudStack's API page size configuration. 142 | if page > 20: 143 | return all_results 144 | 145 | if result[response_key].get('count', 0) >= self._page_size: 146 | page += 1 147 | d = self._request_single( 148 | command, page=page, pagesize=self._page_size, **kwargs) 149 | 150 | d.addCallback( 151 | self._request_page, page, all_results, command, **kwargs) 152 | 153 | return d 154 | else: 155 | return all_results 156 | 157 | @defer.inlineCallbacks 158 | def _request(self, command, **kwargs): 159 | if command.startswith('list'): 160 | all_results = {} 161 | 162 | if not self._page_size: 163 | yield self._get_page_size() 164 | 165 | result = yield self._request_page(None, 0, all_results, command, **kwargs) 166 | else: 167 | result = yield self._request_single(command, **kwargs) 168 | 169 | defer.returnValue(result) 170 | 171 | def listConfigurations(self, **kwargs): 172 | return self._request('listConfigurations', **kwargs) 173 | 174 | def listDomains(self, **kwargs): 175 | return self._request('listDomains', **kwargs) 176 | 177 | def listDomainChildren(self, **kwargs): 178 | return self._request('listDomainChildren', **kwargs) 179 | 180 | def listZones(self, **kwargs): 181 | return self._request('listZones', **kwargs) 182 | 183 | def listPods(self, **kwargs): 184 | return self._request('listPods', **kwargs) 185 | 186 | def listClusters(self, **kwargs): 187 | return self._request('listClusters', **kwargs) 188 | 189 | def listHosts(self, **kwargs): 190 | return self._request('listHosts', **kwargs) 191 | 192 | def listSystemVms(self, **kwargs): 193 | return self._request('listSystemVms', **kwargs) 194 | 195 | def listRouters(self, **kwargs): 196 | return self._request('listRouters', **kwargs) 197 | 198 | def listVirtualMachines(self, **kwargs): 199 | return self._request('listVirtualMachines', **kwargs) 200 | 201 | def listCapacity(self, **kwargs): 202 | return self._request('listCapacity', **kwargs) 203 | 204 | def listAlerts(self, **kwargs): 205 | return self._request('listAlerts', **kwargs) 206 | 207 | def listEvents(self, **kwargs): 208 | return self._request('listEvents', **kwargs) 209 | 210 | 211 | if __name__ == '__main__': 212 | import os 213 | import sys 214 | 215 | from twisted.internet import reactor 216 | from twisted.internet.defer import DeferredList 217 | 218 | client = Client( 219 | os.environ.get('CLOUDSTACK_URL', 'http://localhost/'), 220 | os.environ.get('CLOUDSTACK_APIKEY', 'asd123'), 221 | os.environ.get('CLOUDSTACK_SECRETKEY', 'asd123')) 222 | 223 | def callback(results): 224 | reactor.stop() 225 | 226 | for success, result in results: 227 | if success: 228 | from pprint import pprint 229 | pprint(result) 230 | elif hasattr(result, 'value') and hasattr(result.value, 'response'): 231 | print result.value.response 232 | else: 233 | print result.getErrorMessage() 234 | 235 | deferreds = [] 236 | if len(sys.argv) < 2: 237 | deferreds.extend(( 238 | client.listConfigurations(name='default.page.size'), 239 | client.listZones(available='true'), 240 | client.listPods(), 241 | client.listClusters(), 242 | client.listHosts(), 243 | client.listSystemVms(), 244 | client.listRouters(listAll='true'), 245 | client.listVirtualMachines(), 246 | client.listCapacity(), 247 | client.listAlerts(), 248 | client.listEvents(), 249 | )) 250 | else: 251 | for command in sys.argv[1:]: 252 | call = getattr(client, command, None) 253 | if call is not None: 254 | if command == 'listConfigurations': 255 | deferreds.append(call(name='default.page.size')) 256 | elif command == 'listHosts': 257 | deferreds.append(call(type='Routing')) 258 | elif command == 'listRouters': 259 | deferreds.append(call(listAll='true')) 260 | elif command == 'listVirtualMachines': 261 | deferreds.append(call(domainid='1', isrecursive=True, state='Running', listAll='true')) 262 | else: 263 | deferreds.append(call()) 264 | 265 | DeferredList(deferreds, consumeErrors=True).addCallback(callback) 266 | reactor.run() 267 | -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/locallibs.py: -------------------------------------------------------------------------------- 1 | ############################################################################## 2 | # 3 | # Copyright (C) Zenoss, Inc. 2013, all rights reserved. 4 | # 5 | # This content is made available according to terms specified in 6 | # License.zenoss under the directory where your Zenoss product is installed. 7 | # 8 | ############################################################################## 9 | 10 | 11 | def add_local_lib_path(): 12 | ''' 13 | Helper to add the ZenPack's lib directory to sys.path. 14 | ''' 15 | import os 16 | import site 17 | 18 | site.addsitedir(os.path.join(os.path.dirname(__file__), 'lib')) 19 | 20 | 21 | add_local_lib_path() 22 | -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/migrate/MigratePassword.py: -------------------------------------------------------------------------------- 1 | ############################################################################## 2 | # Copyright (C) Zenoss, Inc. 2015, all rights reserved. 3 | # 4 | # This content is made available according to terms specified in 5 | # License.zenoss under the directory where your Zenoss product is installed. 6 | ############################################################################## 7 | 8 | import logging 9 | log = logging.getLogger("zen.migrate") 10 | 11 | import Globals 12 | from Products.ZenModel.migrate.Migrate import Version 13 | from Products.ZenModel.ZenPack import ZenPackMigration 14 | from Products.ZenModel.migrate.MigrateUtils import migratePropertyType 15 | 16 | 17 | class MigratePassword(ZenPackMigration): 18 | version = Version(1, 2, 0) 19 | 20 | def migrate(self, dmd): 21 | log.info("Migrating zCloudStackSecretKey") 22 | migratePropertyType("zCloudStackSecretKey", dmd, "string") 23 | 24 | MigratePassword() 25 | -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/migrate/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenoss/ZenPacks.zenoss.CloudStack/a3156e7f13f3cd04a4cbc588c3d36d036b696a34/ZenPacks/zenoss/CloudStack/migrate/__init__.py -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/modeler/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenoss/ZenPacks.zenoss.CloudStack/a3156e7f13f3cd04a4cbc588c3d36d036b696a34/ZenPacks/zenoss/CloudStack/modeler/__init__.py -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/modeler/plugins/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenoss/ZenPacks.zenoss.CloudStack/a3156e7f13f3cd04a4cbc588c3d36d036b696a34/ZenPacks/zenoss/CloudStack/modeler/plugins/__init__.py -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/modeler/plugins/zenoss/CloudStack.py: -------------------------------------------------------------------------------- 1 | ########################################################################### 2 | # 3 | # This program is part of Zenoss Core, an open source monitoring platform. 4 | # Copyright (C) 2011, 2012 Zenoss Inc. 5 | # 6 | # This program is free software; you can redistribute it and/or modify it 7 | # under the terms of the GNU General Public License version 2 or (at your 8 | # option) any later version as published by the Free Software Foundation. 9 | # 10 | # For complete information please visit: http://www.zenoss.com/oss/ 11 | # 12 | ########################################################################### 13 | 14 | import logging 15 | LOG = logging.getLogger('zen.CloudStack') 16 | 17 | import json 18 | 19 | from twisted.internet.defer import DeferredList 20 | 21 | from Products.DataCollector.plugins.CollectorPlugin import PythonPlugin 22 | from Products.DataCollector.plugins.DataMaps import ObjectMap, RelationshipMap 23 | 24 | # Imported or side effect of adding ZenPack's lib directory to sys.path. 25 | import ZenPacks.zenoss.CloudStack.locallibs 26 | 27 | # Requires that locallibs first be imported. 28 | import txcloudstack 29 | 30 | 31 | class CloudStack(PythonPlugin): 32 | deviceProperties = PythonPlugin.deviceProperties + ( 33 | 'zCloudStackURL', 34 | 'zCloudStackAPIKey', 35 | 'zCloudStackSecretKey', 36 | ) 37 | 38 | def collect(self, device, unused): 39 | """Collect model-related information using the txcloudstack library. 40 | 41 | Note: This method is not currently unit tested because we haven't gone 42 | to the trouble of creating mock results within txcloudstack. 43 | """ 44 | if not device.zCloudStackURL: 45 | LOG.error('zCloudStackURL is not set. Not discovering') 46 | return None 47 | 48 | if not device.zCloudStackAPIKey: 49 | LOG.error('zCloudStackAPIKey is not set. Not discovering.') 50 | return None 51 | 52 | if not device.zCloudStackSecretKey: 53 | LOG.error('zCloudStackSecretKey is not set. Not discovering.') 54 | return None 55 | 56 | client = txcloudstack.Client( 57 | device.zCloudStackURL, 58 | device.zCloudStackAPIKey, 59 | device.zCloudStackSecretKey) 60 | 61 | d = DeferredList(( 62 | client.listZones(), 63 | client.listPods(), 64 | client.listClusters(), 65 | client.listHosts(type="Routing"), 66 | client.listSystemVms(), 67 | client.listRouters(listAll='true'), 68 | client.listVirtualMachines(isrecursive=True, listAll='true'), 69 | client.listCapacity(), 70 | ), consumeErrors=True).addCallback(self._combine) 71 | 72 | return d 73 | 74 | def _combine(self, results): 75 | """Combines all responses within results into a single data structure. 76 | 77 | Note: This method is not currently unit tested because we haven't gone 78 | to the trouble of creating mock results within txcloudstack. 79 | """ 80 | all_data = {} 81 | 82 | for success, result in results: 83 | # we cannot return None simply when some API calls fail, 84 | # because not all users have permissions to call every API 85 | # instead we update all_data only for those successful API calls 86 | # where result is a dict rather than twisted.python.failure.Failure 87 | if not success: 88 | if hasattr(result, 'value') and hasattr(result.value, 'response'): 89 | response = json.loads(result.value.response) 90 | 91 | if response.get('errorresponse', None) and \ 92 | response['errorresponse'].get('errortext', None): 93 | if 'does not exist' not in \ 94 | response['errorresponse']['errortext']: 95 | LOG.error("API Error: %s", result.getErrorMessage()) 96 | else: 97 | LOG.debug("%s", response['errorresponse']['errortext']) 98 | elif response[response.keys()[0]].get('errortext', None): 99 | LOG.debug("%s", response[response.keys()[0]]['errortext']) 100 | else: 101 | LOG.error("API Error: %s", result.getErrorMessage()) 102 | 103 | if isinstance(result, dict): 104 | all_data.update(result) 105 | 106 | return all_data 107 | 108 | def process(self, device, results, unused): 109 | maps = [] 110 | 111 | response_types = ( 112 | 'zones', 'pods', 'clusters', 'hosts', 'systemvms', 'routers', 113 | 'virtualmachines', 114 | ) 115 | 116 | for t in response_types: 117 | rel_maps = None 118 | response = results.get('list%sresponse' % t, None) 119 | if response is None: 120 | LOG.debug('No list%s response from API', t.capitalize()) 121 | else: 122 | rel_maps = tuple(getattr(self, 'get_%s_rel_maps' % t)(response)) 123 | count = reduce(lambda x, y: x + len(y.maps), rel_maps, 0) 124 | LOG.info('Found %s %s', count, t) 125 | 126 | if rel_maps: 127 | maps.extend(rel_maps) 128 | 129 | return maps 130 | 131 | def get_zones_rel_maps(self, zones_response): 132 | zone_maps = [] 133 | for zone in zones_response.get('zone', []): 134 | if not zone.get('id', None): 135 | continue 136 | 137 | zone_id = self.prepId('zone%s' % zone['id']) 138 | 139 | zone_maps.append(ObjectMap(data=dict( 140 | id=zone_id, 141 | title=zone.get('name', zone_id), 142 | cloudstack_id=zone['id'], 143 | allocation_state=zone.get('allocationstate', ''), 144 | guest_cidr_address=zone.get('guestcidraddress', ''), 145 | dhcp_provider=zone.get('dhcpprovider', ''), 146 | dns1=zone.get('dns1', ''), 147 | dns2=zone.get('dns2', ''), 148 | internal_dns1=zone.get('internaldns1', ''), 149 | internal_dns2=zone.get('internaldns2', ''), 150 | network_type=zone.get('networktype', ''), 151 | security_groups_enabled=zone.get('securitygroupsenabled', ''), 152 | vlan=zone.get('vlan', ''), 153 | zone_token=zone.get('zonetoken', ''), 154 | ))) 155 | 156 | yield RelationshipMap( 157 | relname='zones', 158 | modname='ZenPacks.zenoss.CloudStack.Zone', 159 | objmaps=zone_maps) 160 | 161 | def get_pods_rel_maps(self, pods_response): 162 | pod_maps = {} 163 | for pod in pods_response.get('pod', []): 164 | if not pod.get('id', None): 165 | continue 166 | 167 | zone_id = self.prepId('zone%s' % pod.get('zoneid', '')) 168 | pod_id = self.prepId('pod%s' % pod['id']) 169 | 170 | compname = 'zones/%s' % zone_id 171 | pod_maps.setdefault(compname, []) 172 | 173 | pod_maps[compname].append(ObjectMap(data=dict( 174 | id=pod_id, 175 | title=pod.get('name', pod_id), 176 | cloudstack_id=pod['id'], 177 | allocation_state=pod.get('allocationstate', ''), 178 | start_ip=pod.get('startip', ''), 179 | end_ip=pod.get('endip', ''), 180 | netmask=pod.get('netmask', ''), 181 | gateway=pod.get('gateway', ''), 182 | ))) 183 | 184 | for compname, obj_maps in pod_maps.items(): 185 | yield RelationshipMap( 186 | compname=compname, 187 | relname='pods', 188 | modname='ZenPacks.zenoss.CloudStack.Pod', 189 | objmaps=obj_maps) 190 | 191 | def get_clusters_rel_maps(self, clusters_response): 192 | cluster_maps = {} 193 | for cluster in clusters_response.get('cluster', []): 194 | if not cluster.get('id', None): 195 | continue 196 | 197 | zone_id = self.prepId('zone%s' % cluster.get('zoneid', '')) 198 | pod_id = self.prepId('pod%s' % cluster.get('podid', '')) 199 | cluster_id = self.prepId('cluster%s' % cluster['id']) 200 | 201 | compname = 'zones/%s/pods/%s' % (zone_id, pod_id) 202 | cluster_maps.setdefault(compname, []) 203 | 204 | cluster_maps[compname].append(ObjectMap(data=dict( 205 | id=cluster_id, 206 | title=cluster.get('name', cluster_id), 207 | cloudstack_id=cluster['id'], 208 | allocation_state=cluster.get('allocationstate', ''), 209 | cluster_type=cluster.get('clustertype', ''), 210 | hypervisor_type=cluster.get('hypervisortype', ''), 211 | managed_state=cluster.get('managedstate', ''), 212 | ))) 213 | 214 | for compname, obj_maps in cluster_maps.items(): 215 | yield RelationshipMap( 216 | compname=compname, 217 | relname='clusters', 218 | modname='ZenPacks.zenoss.CloudStack.Cluster', 219 | objmaps=obj_maps) 220 | 221 | def get_hosts_rel_maps(self, hosts_response): 222 | host_maps = {} 223 | for host in hosts_response.get('host', []): 224 | if not host.get('id', None): 225 | continue 226 | 227 | host_type = host.get('type', None) 228 | 229 | zone_id = self.prepId('zone%s' % host.get('zoneid', '')) 230 | pod_id = self.prepId('pod%s' % host.get('podid', '')) 231 | cluster_id = self.prepId('cluster%s' % host.get('clusterid', '')) 232 | host_id = self.prepId('host%s' % host['id']) 233 | 234 | compname = 'zones/%s/pods/%s/clusters/%s' % ( 235 | zone_id, pod_id, cluster_id) 236 | 237 | host_maps.setdefault(compname, []) 238 | 239 | host_maps[compname].append(ObjectMap(data=dict( 240 | id=host_id, 241 | title=host.get('name', host_id), 242 | cloudstack_id=host['id'], 243 | allocation_state=host.get('allocationstate', ''), 244 | host_type=host_type, 245 | host_state=host.get('state', ''), 246 | host_events=host.get('events', ''), 247 | host_version=host.get('version', ''), 248 | hypervisor=host.get('hypervisor', ''), 249 | capabilities=host.get('capabilities', ''), 250 | created=host.get('created', ''), 251 | host_tags=host.get('hosttags', ''), 252 | ip_address=host.get('ipaddress', ''), 253 | local_storage_active=host.get('islocalstorageactive', None), 254 | management_server_id=host.get('managementserverid', None), 255 | ))) 256 | 257 | for compname, obj_maps in host_maps.items(): 258 | yield RelationshipMap( 259 | compname=compname, 260 | relname='hosts', 261 | modname='ZenPacks.zenoss.CloudStack.Host', 262 | objmaps=obj_maps) 263 | 264 | def get_systemvms_rel_maps(self, systemvms_response): 265 | systemvm_maps = {} 266 | for systemvm in systemvms_response.get('systemvm', []): 267 | if not systemvm.get('id', None): 268 | continue 269 | 270 | zone_id = self.prepId('zone%s' % systemvm.get('zoneid', '')) 271 | pod_id = self.prepId('pod%s' % systemvm.get('podid', '')) 272 | systemvm_id = self.prepId('systemvm%s' % systemvm['id']) 273 | 274 | compname = 'zones/%s/pods/%s' % (zone_id, pod_id) 275 | 276 | systemvm_maps.setdefault(compname, []) 277 | 278 | systemvm_maps[compname].append(ObjectMap(data=dict( 279 | id=systemvm_id, 280 | title=systemvm.get('name', systemvm_id), 281 | cloudstack_id=systemvm['id'], 282 | gateway=systemvm.get('gateway', ''), 283 | linklocal_ip=systemvm.get('linklocalip', ''), 284 | linklocal_macaddress=systemvm.get('linklocalmacaddress', ''), 285 | linklocal_netmask=systemvm.get('linklocalnetmask', ''), 286 | network_domain=systemvm.get('networkdomain', ''), 287 | private_ip=systemvm.get('privateip', ''), 288 | private_macaddress=systemvm.get('privatemacaddress', ''), 289 | private_netmask=systemvm.get('privatenetmask', ''), 290 | public_ip=systemvm.get('publicip', ''), 291 | public_macaddress=systemvm.get('publicmacaddress', ''), 292 | public_netmask=systemvm.get('publicnetmask', ''), 293 | systemvm_type=systemvm.get('systemvmtype', ''), 294 | template_id=systemvm.get('templateid', None), 295 | setHostId=systemvm.get('hostid', None), 296 | ))) 297 | 298 | for compname, obj_maps in systemvm_maps.items(): 299 | yield RelationshipMap( 300 | compname=compname, 301 | relname='systemvms', 302 | modname='ZenPacks.zenoss.CloudStack.SystemVM', 303 | objmaps=obj_maps) 304 | 305 | def get_routers_rel_maps(self, routers_response): 306 | routervm_maps = {} 307 | for routervm in routers_response.get('router', []): 308 | if not routervm.get('id', None): 309 | continue 310 | 311 | zone_id = self.prepId('zone%s' % routervm.get('zoneid', '')) 312 | pod_id = self.prepId('pod%s' % routervm.get('podid', '')) 313 | routervm_id = self.prepId('routervm%s' % routervm['id']) 314 | 315 | compname = 'zones/%s/pods/%s' % (zone_id, pod_id) 316 | 317 | routervm_maps.setdefault(compname, []) 318 | 319 | routervm_maps[compname].append(ObjectMap(data=dict( 320 | id=routervm_id, 321 | title=routervm.get('name', routervm_id), 322 | cloudstack_id=routervm['id'], 323 | account=routervm.get('account', ''), 324 | created=routervm.get('created', ''), 325 | dns1=routervm.get('dns1', ''), 326 | dns2=routervm.get('dns2', ''), 327 | domain=routervm.get('domain', ''), 328 | gateway=routervm.get('gateway', ''), 329 | guest_ip=routervm.get('guestip', ''), 330 | guest_macaddress=routervm.get('guestmacaddress', ''), 331 | guest_netmask=routervm.get('guestnetmask', ''), 332 | linklocal_ip=routervm.get('linklocalip', ''), 333 | linklocal_macaddress=routervm.get('linklocalmacaddress', ''), 334 | linklocal_netmask=routervm.get('linklocalnetmask', ''), 335 | network_domain=routervm.get('networkdomain', ''), 336 | public_ip=routervm.get('publicip', ''), 337 | public_macaddress=routervm.get('publicmacaddress', ''), 338 | public_netmask=routervm.get('publicnetmask', ''), 339 | state=routervm.get('state', ''), 340 | template_id=routervm.get('templateid', None), 341 | setHostId=routervm.get('hostid', None), 342 | ))) 343 | 344 | for compname, obj_maps in routervm_maps.items(): 345 | yield RelationshipMap( 346 | compname=compname, 347 | relname='routervms', 348 | modname='ZenPacks.zenoss.CloudStack.RouterVM', 349 | objmaps=obj_maps) 350 | 351 | def get_virtualmachines_rel_maps(self, vms_response): 352 | vm_maps = {} 353 | 354 | # Used to avoid creating duplicate VMs from duplicate VMs in the 355 | # response. 356 | vm_ids = set() 357 | 358 | for vm in vms_response.get('virtualmachine', []): 359 | if not vm.get('id', None): 360 | continue 361 | 362 | zone_id = self.prepId('zone%s' % vm.get('zoneid', '')) 363 | vm_id = self.prepId('vm%s' % vm['id']) 364 | 365 | if vm_id in vm_ids: 366 | continue 367 | 368 | vm_ids.add(vm_id) 369 | 370 | compname = 'zones/%s' % zone_id 371 | 372 | vm_maps.setdefault(compname, []) 373 | 374 | memory = None 375 | if 'memory' in vm: 376 | memory = vm['memory'] * (1024 ** 2) 377 | 378 | mac_address = '' 379 | ip_address = '' 380 | netmask = '' 381 | gateway = '' 382 | 383 | for nic in vm.get('nic', []): 384 | if nic.get('isdefault', False): 385 | mac_address = nic.get('macaddress', '') 386 | ip_address = nic.get('ipaddress', '') 387 | netmask = nic.get('netmask', '') 388 | gateway = nic.get('gateway', '') 389 | 390 | vm_maps[compname].append(ObjectMap(data=dict( 391 | id=vm_id, 392 | title=vm.get('name', vm_id), 393 | cloudstack_id=vm['id'], 394 | account=vm.get('account', ''), 395 | cpu_number=vm.get('cpunumber', None), 396 | cpu_speed=vm.get('cpuspeed', None), 397 | created=vm.get('created', ''), 398 | display_name=vm.get('displayname', ''), 399 | domain=vm.get('domain', ''), 400 | ha_enable=vm.get('haenable', False), 401 | setHostId=vm.get('hostid', None), 402 | memory=memory, 403 | mac_address=mac_address, 404 | ip_address=ip_address, 405 | netmask=netmask, 406 | gateway=gateway, 407 | root_device_type=vm.get('rootdevicetype', ''), 408 | service_offering=vm.get('serviceofferingname', ''), 409 | state=vm.get('state', ''), 410 | template=vm.get('templatename', ''), 411 | ))) 412 | 413 | for compname, obj_maps in vm_maps.items(): 414 | yield RelationshipMap( 415 | compname=compname, 416 | relname='vms', 417 | modname='ZenPacks.zenoss.CloudStack.VirtualMachine', 418 | objmaps=obj_maps) 419 | -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/modeler/plugins/zenoss/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenoss/ZenPacks.zenoss.CloudStack/a3156e7f13f3cd04a4cbc588c3d36d036b696a34/ZenPacks/zenoss/CloudStack/modeler/plugins/zenoss/__init__.py -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/parsers/CloudStack.py: -------------------------------------------------------------------------------- 1 | ########################################################################### 2 | # 3 | # This program is part of Zenoss Core, an open source monitoring platform. 4 | # Copyright (C) 2011, Zenoss Inc. 5 | # 6 | # This program is free software; you can redistribute it and/or modify it 7 | # under the terms of the GNU General Public License version 2 or (at your 8 | # option) any later version as published by the Free Software Foundation. 9 | # 10 | # For complete information please visit: http://www.zenoss.com/oss/ 11 | # 12 | ########################################################################### 13 | 14 | import json 15 | 16 | from Products.ZenRRD.CommandParser import CommandParser 17 | 18 | 19 | def stringify_keys(dictionary): 20 | """Convert all keys of given dictionary to strings.""" 21 | fixed_dictionary = {} 22 | for k, v in dictionary.items(): 23 | fixed_dictionary[str(k)] = v 24 | 25 | return fixed_dictionary 26 | 27 | 28 | class CloudStack(CommandParser): 29 | def processResults(self, cmd, result): 30 | if 'poll_cloudstack' not in cmd.command: 31 | return 32 | 33 | data = None 34 | try: 35 | data = json.loads(cmd.result.output) 36 | except Exception, ex: 37 | result.events.append(dict( 38 | severity=4, 39 | summary='error parsing command results', 40 | message='error parsing command results: %s' % ex, 41 | eventKey='cloudstack_failure', 42 | eventClassKey='cloudstack_parse_error', 43 | )) 44 | 45 | return 46 | 47 | # Pass incoming events straight through. 48 | result.events.extend(map(stringify_keys, data.get('events', []))) 49 | 50 | # Map incoming values to their components and datapoints. 51 | if len(data.get('values', {}).keys()) > 0: 52 | for point in cmd.points: 53 | if point.component not in data['values']: 54 | continue 55 | 56 | if point.id not in data['values'][point.component]: 57 | continue 58 | 59 | result.values.append(( 60 | point, data['values'][point.component][point.id])) 61 | 62 | return result 63 | -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/parsers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenoss/ZenPacks.zenoss.CloudStack/a3156e7f13f3cd04a4cbc588c3d36d036b696a34/ZenPacks/zenoss/CloudStack/parsers/__init__.py -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/routers.py: -------------------------------------------------------------------------------- 1 | ########################################################################### 2 | # 3 | # This program is part of Zenoss Core, an open source monitoring platform. 4 | # Copyright (C) 2011, Zenoss Inc. 5 | # 6 | # This program is free software; you can redistribute it and/or modify it 7 | # under the terms of the GNU General Public License version 2 or (at your 8 | # option) any later version as published by the Free Software Foundation. 9 | # 10 | # For complete information please visit: http://www.zenoss.com/oss/ 11 | # 12 | ########################################################################### 13 | 14 | from Products.ZenUtils.Ext import DirectRouter, DirectResponse 15 | from Products import Zuul 16 | from Products.ZenMessaging.audit import audit 17 | 18 | 19 | class CloudStackRouter(DirectRouter): 20 | def _getFacade(self): 21 | return Zuul.getFacade('cloudstack', self.context) 22 | 23 | def add_cloudstack(self, device_name, url, api_key, secret_key,collector='localhost'): 24 | 25 | facade = self._getFacade() 26 | success = facade.add_cloudstack( 27 | device_name, url, api_key, secret_key,collector) 28 | 29 | audit('UI.Cloudstack.Add', url=url, collector=collector) 30 | if success: 31 | return DirectResponse.succeed() 32 | else: 33 | return DirectResponse.fail("Failed to add CloudStack device: %s" % device_name) 34 | -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/tests/__init__.py: -------------------------------------------------------------------------------- 1 | # ########################################################################## 2 | # 3 | # This program is part of Zenoss Core, an open source monitoring platform. 4 | # Copyright (C) 2008, Zenoss Inc. 5 | # 6 | # This program is free software; you can redistribute it and/or modify it 7 | # under the terms of the GNU General Public License version 2 as published by 8 | # the Free Software Foundation. 9 | # 10 | # For complete information please visit: http://www.zenoss.com/oss/ 11 | # 12 | # ########################################################################## 13 | -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/tests/data/cloudstack_results_missingHosts.pickle: -------------------------------------------------------------------------------- 1 | (dp0 2 | S'listclustersresponse' 3 | p1 4 | (dp2 5 | Vcount 6 | p3 7 | I3 8 | sVcluster 9 | p4 10 | (lp5 11 | (dp6 12 | Vmanagedstate 13 | p7 14 | VManaged 15 | p8 16 | sVname 17 | p9 18 | VXenCluster1-D5 19 | p10 20 | sVhypervisortype 21 | p11 22 | VXenServer 23 | p12 24 | sVpodid 25 | p13 26 | I1 27 | sVclustertype 28 | p14 29 | VCloudManaged 30 | p15 31 | sVallocationstate 32 | p16 33 | VEnabled 34 | p17 35 | sVzoneid 36 | p18 37 | I1 38 | sVpodname 39 | p19 40 | VPod-A 41 | p20 42 | sVid 43 | p21 44 | I1 45 | sVzonename 46 | p22 47 | VDemo5 48 | p23 49 | sa(dp24 50 | Vmanagedstate 51 | p25 52 | VManaged 53 | p26 54 | sVname 55 | p27 56 | Vbaremetal delete me 57 | p28 58 | sVhypervisortype 59 | p29 60 | VBareMetal 61 | p30 62 | sVpodid 63 | p31 64 | I1 65 | sVclustertype 66 | p32 67 | VCloudManaged 68 | p33 69 | sVallocationstate 70 | p34 71 | VEnabled 72 | p35 73 | sVzoneid 74 | p36 75 | I1 76 | sVpodname 77 | p37 78 | VPod-A 79 | p38 80 | sVid 81 | p39 82 | I2 83 | sVzonename 84 | p40 85 | VDemo5 86 | p41 87 | sa(dp42 88 | Vmanagedstate 89 | p43 90 | VManaged 91 | p44 92 | sVname 93 | p45 94 | Vkevin test 95 | p46 96 | sVhypervisortype 97 | p47 98 | VBareMetal 99 | p48 100 | sVpodid 101 | p49 102 | I1 103 | sVclustertype 104 | p50 105 | VCloudManaged 106 | p51 107 | sVallocationstate 108 | p52 109 | VEnabled 110 | p53 111 | sVzoneid 112 | p54 113 | I1 114 | sVpodname 115 | p55 116 | VPod-A 117 | p56 118 | sVid 119 | p57 120 | I3 121 | sVzonename 122 | p58 123 | VDemo5 124 | p59 125 | sassS'listzonesresponse' 126 | p60 127 | (dp61 128 | Vcount 129 | p62 130 | I1 131 | sVzone 132 | p63 133 | (lp64 134 | (dp65 135 | Vname 136 | p66 137 | VDemo5 138 | p67 139 | sVguestcidraddress 140 | p68 141 | V10.1.1.0/24 142 | p69 143 | sVzonetoken 144 | p70 145 | Vf0c6542e-7a1a-39b3-8c92-1a1c67cede0b 146 | p71 147 | sVdns1 148 | p72 149 | V72.52.126.11 150 | p73 151 | sVvlan 152 | p74 153 | V1000-1200 154 | p75 155 | sVsecuritygroupsenabled 156 | p76 157 | I00 158 | sVallocationstate 159 | p77 160 | VEnabled 161 | p78 162 | sVid 163 | p79 164 | I1 165 | sVdhcpprovider 166 | p80 167 | VVirtualRouter 168 | p81 169 | sVnetworktype 170 | p82 171 | VAdvanced 172 | p83 173 | sVinternaldns1 174 | p84 175 | V72.52.126.12 176 | p85 177 | sassS'listcapacityresponse' 178 | p86 179 | (dp87 180 | Vcount 181 | p88 182 | I12 183 | sVcapacity 184 | p89 185 | (lp90 186 | (dp91 187 | Vpodid 188 | p92 189 | I-1 190 | sVcapacityused 191 | p93 192 | I16500 193 | sVzoneid 194 | p94 195 | I1 196 | sVpodname 197 | p95 198 | VAll 199 | p96 200 | sVpercentused 201 | p97 202 | V93.75 203 | p98 204 | sVcapacitytotal 205 | p99 206 | I17600 207 | sVtype 208 | p100 209 | I1 210 | sVzonename 211 | p101 212 | VDemo5 213 | p102 214 | sa(dp103 215 | Vpodid 216 | p104 217 | I1 218 | sVcapacityused 219 | p105 220 | I13153337344 221 | sVzoneid 222 | p106 223 | I1 224 | sVpodname 225 | p107 226 | VPod-A 227 | p108 228 | sVpercentused 229 | p109 230 | V40.62 231 | p110 232 | sVcapacitytotal 233 | p111 234 | I32379580416 235 | sVtype 236 | p112 237 | I0 238 | sVzonename 239 | p113 240 | VDemo5 241 | p114 242 | sa(dp115 243 | Vpodid 244 | p116 245 | I1 246 | sVcapacityused 247 | p117 248 | I16500 249 | sVzoneid 250 | p118 251 | I1 252 | sVpodname 253 | p119 254 | VPod-A 255 | p120 256 | sVpercentused 257 | p121 258 | V93.75 259 | p122 260 | sVcapacitytotal 261 | p123 262 | I17600 263 | sVtype 264 | p124 265 | I1 266 | sVzonename 267 | p125 268 | VDemo5 269 | p126 270 | sa(dp127 271 | Vpodid 272 | p128 273 | I1 274 | sVcapacityused 275 | p129 276 | I760708136960 277 | sVzoneid 278 | p130 279 | I1 280 | sVpodname 281 | p131 282 | VPod-A 283 | p132 284 | sVpercentused 285 | p133 286 | V20.35 287 | p134 288 | sVcapacitytotal 289 | p135 290 | I3738339639296 291 | sVtype 292 | p136 293 | I2 294 | sVzonename 295 | p137 296 | VDemo5 297 | p138 298 | sa(dp139 299 | Vcapacityused 300 | p140 301 | I15 302 | sVcapacitytotal 303 | p141 304 | I59 305 | sVpercentused 306 | p142 307 | V25.42 308 | p143 309 | sVzoneid 310 | p144 311 | I1 312 | sVtype 313 | p145 314 | I4 315 | sVzonename 316 | p146 317 | VDemo5 318 | p147 319 | sa(dp148 320 | Vpodid 321 | p149 322 | I-1 323 | sVcapacityused 324 | p150 325 | I283987935232 326 | sVzoneid 327 | p151 328 | I1 329 | sVpodname 330 | p152 331 | VAll 332 | p153 333 | sVpercentused 334 | p154 335 | V4.45 336 | p155 337 | sVcapacitytotal 338 | p156 339 | I6377167650816 340 | sVtype 341 | p157 342 | I3 343 | sVzonename 344 | p158 345 | VDemo5 346 | p159 347 | sa(dp160 348 | Vpodid 349 | p161 350 | I-1 351 | sVcapacityused 352 | p162 353 | I760708136960 354 | sVzoneid 355 | p163 356 | I1 357 | sVpodname 358 | p164 359 | VAll 360 | p165 361 | sVpercentused 362 | p166 363 | V20.35 364 | p167 365 | sVcapacitytotal 366 | p168 367 | I3738339639296 368 | sVtype 369 | p169 370 | I2 371 | sVzonename 372 | p170 373 | VDemo5 374 | p171 375 | sa(dp172 376 | Vpodid 377 | p173 378 | I1 379 | sVcapacityused 380 | p174 381 | I2 382 | sVzoneid 383 | p175 384 | I1 385 | sVpodname 386 | p176 387 | VPod-A 388 | p177 389 | sVpercentused 390 | p178 391 | V9.52 392 | p179 393 | sVcapacitytotal 394 | p180 395 | I21 396 | sVtype 397 | p181 398 | I5 399 | sVzonename 400 | p182 401 | VDemo5 402 | p183 403 | sa(dp184 404 | Vpodid 405 | p185 406 | I-1 407 | sVcapacityused 408 | p186 409 | I2 410 | sVzoneid 411 | p187 412 | I1 413 | sVpodname 414 | p188 415 | VAll 416 | p189 417 | sVpercentused 418 | p190 419 | V9.52 420 | p191 421 | sVcapacitytotal 422 | p192 423 | I21 424 | sVtype 425 | p193 426 | I5 427 | sVzonename 428 | p194 429 | VDemo5 430 | p195 431 | sa(dp196 432 | Vcapacityused 433 | p197 434 | I685793542144 435 | sVcapacitytotal 436 | p198 437 | I2638828011520 438 | sVpercentused 439 | p199 440 | V25.99 441 | p200 442 | sVzoneid 443 | p201 444 | I1 445 | sVtype 446 | p202 447 | I6 448 | sVzonename 449 | p203 450 | VDemo5 451 | p204 452 | sa(dp205 453 | Vpodid 454 | p206 455 | I1 456 | sVcapacityused 457 | p207 458 | I283987935232 459 | sVzoneid 460 | p208 461 | I1 462 | sVpodname 463 | p209 464 | VPod-A 465 | p210 466 | sVpercentused 467 | p211 468 | V4.45 469 | p212 470 | sVcapacitytotal 471 | p213 472 | I6377167650816 473 | sVtype 474 | p214 475 | I3 476 | sVzonename 477 | p215 478 | VDemo5 479 | p216 480 | sa(dp217 481 | Vpodid 482 | p218 483 | I-1 484 | sVcapacityused 485 | p219 486 | I13153337344 487 | sVzoneid 488 | p220 489 | I1 490 | sVpodname 491 | p221 492 | VAll 493 | p222 494 | sVpercentused 495 | p223 496 | V40.62 497 | p224 498 | sVcapacitytotal 499 | p225 500 | I32379580416 501 | sVtype 502 | p226 503 | I0 504 | sVzonename 505 | p227 506 | VDemo5 507 | p228 508 | sassS'listpodsresponse' 509 | p229 510 | (dp230 511 | Vcount 512 | p231 513 | I1 514 | sVpod 515 | p232 516 | (lp233 517 | (dp234 518 | Vendip 519 | p235 520 | V10.208.37.120 521 | p236 522 | sVname 523 | p237 524 | VPod-A 525 | p238 526 | sVstartip 527 | p239 528 | V10.208.37.100 529 | p240 530 | sVallocationstate 531 | p241 532 | VEnabled 533 | p242 534 | sVzoneid 535 | p243 536 | I1 537 | sVnetmask 538 | p244 539 | V255.255.255.128 540 | p245 541 | sVid 542 | p246 543 | I1 544 | sVgateway 545 | p247 546 | V10.208.37.1 547 | p248 548 | sVzonename 549 | p249 550 | VDemo5 551 | p250 552 | sass. -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/tests/data/cloudstack_results_noZones.pickle: -------------------------------------------------------------------------------- 1 | (dp0 2 | S'listhostsresponse' 3 | p1 4 | (dp2 5 | Vcount 6 | p3 7 | I2 8 | sVhost 9 | p4 10 | (lp5 11 | (dp6 12 | Vcpuwithoverprovisioning 13 | p7 14 | V8800.0 15 | p8 16 | sVhasEnoughCapacity 17 | p9 18 | I00 19 | sVversion 20 | p10 21 | V2.2.12.20110927185324 22 | p11 23 | sVmemorytotal 24 | p12 25 | I16189790400 26 | sVallocationstate 27 | p13 28 | VEnabled 29 | p14 30 | sVzoneid 31 | p15 32 | I1 33 | sVcpunumber 34 | p16 35 | I4 36 | sVmanagementserverid 37 | p17 38 | I257544418526661 39 | sVlastpinged 40 | p18 41 | V1970-01-15T13:48:52-0800 42 | p19 43 | sVmemoryused 44 | p20 45 | I7247757312 46 | sVid 47 | p21 48 | I1 49 | sVnetworkkbswrite 50 | p22 51 | I0 52 | sVclusterid 53 | p23 54 | I1 55 | sVcapabilities 56 | p24 57 | Vxen-3.0-x86_64 , xen-3.0-x86_32p , hvm-3.0-x86_32 , hvm-3.0-x86_32p , hvm-3.0-x86_64 58 | p25 59 | sVstate 60 | p26 61 | VUp 62 | p27 63 | sVmemoryallocated 64 | p28 65 | I7247757312 66 | sVcpuused 67 | p29 68 | V0.29% 69 | p30 70 | sVcpuspeed 71 | p31 72 | I2200 73 | sVtype 74 | p32 75 | VRouting 76 | p33 77 | sVevents 78 | p34 79 | VPing; PrepareUnmanaged; PingTimeout; AgentDisconnected; HypervisorVersionChanged; StartAgentRebalance; HostDown; ShutdownRequested; MaintenanceRequested; ManagementServerDown; AgentConnected 80 | p35 81 | sVzonename 82 | p36 83 | VDemo5 84 | p37 85 | sVpodid 86 | p38 87 | I1 88 | sVclustertype 89 | p39 90 | VCloudManaged 91 | p40 92 | sVcpuallocated 93 | p41 94 | V68.18% 95 | p42 96 | sVipaddress 97 | p43 98 | V10.208.37.11 99 | p44 100 | sVname 101 | p45 102 | Vdemo5-xen 103 | p46 104 | sVdisconnected 105 | p47 106 | V2011-10-17T22:02:39-0700 107 | p48 108 | sVnetworkkbsread 109 | p49 110 | I0 111 | sVcreated 112 | p50 113 | V2011-10-17T21:19:45-0700 114 | p51 115 | sVclustername 116 | p52 117 | VXenCluster1-D5 118 | p53 119 | sVhypervisor 120 | p54 121 | VXenServer 122 | p55 123 | sVislocalstorageactive 124 | p56 125 | I00 126 | sVhosttags 127 | p57 128 | V 129 | p58 130 | sVpodname 131 | p59 132 | VPod-A 133 | p60 134 | sa(dp61 135 | Vcpuwithoverprovisioning 136 | p62 137 | V8800.0 138 | p63 139 | sVhasEnoughCapacity 140 | p64 141 | I00 142 | sVversion 143 | p65 144 | V2.2.12.20110927185324 145 | p66 146 | sVmemorytotal 147 | p67 148 | I16189790400 149 | sVallocationstate 150 | p68 151 | VEnabled 152 | p69 153 | sVzoneid 154 | p70 155 | I1 156 | sVcpunumber 157 | p71 158 | I4 159 | sVmanagementserverid 160 | p72 161 | I257544418526661 162 | sVlastpinged 163 | p73 164 | V1970-01-15T13:48:52-0800 165 | p74 166 | sVmemoryused 167 | p75 168 | I5905580032 169 | sVid 170 | p76 171 | I5 172 | sVnetworkkbswrite 173 | p77 174 | I0 175 | sVclusterid 176 | p78 177 | I1 178 | sVcapabilities 179 | p79 180 | Vxen-3.0-x86_64 , xen-3.0-x86_32p , hvm-3.0-x86_32 , hvm-3.0-x86_32p , hvm-3.0-x86_64 181 | p80 182 | sVstate 183 | p81 184 | VUp 185 | p82 186 | sVmemoryallocated 187 | p83 188 | I5905580032 189 | sVcpuused 190 | p84 191 | V0.03% 192 | p85 193 | sVcpuspeed 194 | p86 195 | I2200 196 | sVtype 197 | p87 198 | VRouting 199 | p88 200 | sVevents 201 | p89 202 | VPing; PrepareUnmanaged; PingTimeout; AgentDisconnected; HypervisorVersionChanged; StartAgentRebalance; HostDown; ShutdownRequested; MaintenanceRequested; ManagementServerDown; AgentConnected 203 | p90 204 | sVzonename 205 | p91 206 | VDemo5 207 | p92 208 | sVpodid 209 | p93 210 | I1 211 | sVclustertype 212 | p94 213 | VCloudManaged 214 | p95 215 | sVcpuallocated 216 | p96 217 | V62.5% 218 | p97 219 | sVipaddress 220 | p98 221 | V10.208.37.12 222 | p99 223 | sVname 224 | p100 225 | Vdemo5-xen2 226 | p101 227 | sVnetworkkbsread 228 | p102 229 | I0 230 | sVcreated 231 | p103 232 | V2011-10-17T22:12:21-0700 233 | p104 234 | sVclustername 235 | p105 236 | VXenCluster1-D5 237 | p106 238 | sVhypervisor 239 | p107 240 | VXenServer 241 | p108 242 | sVislocalstorageactive 243 | p109 244 | I00 245 | sVhosttags 246 | p110 247 | g58 248 | sVpodname 249 | p111 250 | VPod-A 251 | p112 252 | sassS'listclustersresponse' 253 | p113 254 | (dp114 255 | Vcount 256 | p115 257 | I3 258 | sVcluster 259 | p116 260 | (lp117 261 | (dp118 262 | Vmanagedstate 263 | p119 264 | VManaged 265 | p120 266 | sVname 267 | p121 268 | VXenCluster1-D5 269 | p122 270 | sVhypervisortype 271 | p123 272 | VXenServer 273 | p124 274 | sVpodid 275 | p125 276 | I1 277 | sVclustertype 278 | p126 279 | VCloudManaged 280 | p127 281 | sVallocationstate 282 | p128 283 | VEnabled 284 | p129 285 | sVzoneid 286 | p130 287 | I1 288 | sVpodname 289 | p131 290 | VPod-A 291 | p132 292 | sVid 293 | p133 294 | I1 295 | sVzonename 296 | p134 297 | VDemo5 298 | p135 299 | sa(dp136 300 | Vmanagedstate 301 | p137 302 | VManaged 303 | p138 304 | sVname 305 | p139 306 | Vbaremetal delete me 307 | p140 308 | sVhypervisortype 309 | p141 310 | VBareMetal 311 | p142 312 | sVpodid 313 | p143 314 | I1 315 | sVclustertype 316 | p144 317 | VCloudManaged 318 | p145 319 | sVallocationstate 320 | p146 321 | VEnabled 322 | p147 323 | sVzoneid 324 | p148 325 | I1 326 | sVpodname 327 | p149 328 | VPod-A 329 | p150 330 | sVid 331 | p151 332 | I2 333 | sVzonename 334 | p152 335 | VDemo5 336 | p153 337 | sa(dp154 338 | Vmanagedstate 339 | p155 340 | VManaged 341 | p156 342 | sVname 343 | p157 344 | Vkevin test 345 | p158 346 | sVhypervisortype 347 | p159 348 | VBareMetal 349 | p160 350 | sVpodid 351 | p161 352 | I1 353 | sVclustertype 354 | p162 355 | VCloudManaged 356 | p163 357 | sVallocationstate 358 | p164 359 | VEnabled 360 | p165 361 | sVzoneid 362 | p166 363 | I1 364 | sVpodname 365 | p167 366 | VPod-A 367 | p168 368 | sVid 369 | p169 370 | I3 371 | sVzonename 372 | p170 373 | VDemo5 374 | p171 375 | sassS'listzonesresponse' 376 | p172 377 | (dp173 378 | Vcount 379 | p174 380 | I0 381 | sVzone 382 | p175 383 | (lp176 384 | ssS'listcapacityresponse' 385 | p177 386 | (dp178 387 | Vcount 388 | p179 389 | I12 390 | sVcapacity 391 | p180 392 | (lp181 393 | (dp182 394 | Vpodid 395 | p183 396 | I-1 397 | sVcapacityused 398 | p184 399 | I16500 400 | sVzoneid 401 | p185 402 | I1 403 | sVpodname 404 | p186 405 | VAll 406 | p187 407 | sVpercentused 408 | p188 409 | V93.75 410 | p189 411 | sVcapacitytotal 412 | p190 413 | I17600 414 | sVtype 415 | p191 416 | I1 417 | sVzonename 418 | p192 419 | VDemo5 420 | p193 421 | sa(dp194 422 | Vpodid 423 | p195 424 | I1 425 | sVcapacityused 426 | p196 427 | I13153337344 428 | sVzoneid 429 | p197 430 | I1 431 | sVpodname 432 | p198 433 | VPod-A 434 | p199 435 | sVpercentused 436 | p200 437 | V40.62 438 | p201 439 | sVcapacitytotal 440 | p202 441 | I32379580416 442 | sVtype 443 | p203 444 | I0 445 | sVzonename 446 | p204 447 | VDemo5 448 | p205 449 | sa(dp206 450 | Vpodid 451 | p207 452 | I1 453 | sVcapacityused 454 | p208 455 | I16500 456 | sVzoneid 457 | p209 458 | I1 459 | sVpodname 460 | p210 461 | VPod-A 462 | p211 463 | sVpercentused 464 | p212 465 | V93.75 466 | p213 467 | sVcapacitytotal 468 | p214 469 | I17600 470 | sVtype 471 | p215 472 | I1 473 | sVzonename 474 | p216 475 | VDemo5 476 | p217 477 | sa(dp218 478 | Vpodid 479 | p219 480 | I1 481 | sVcapacityused 482 | p220 483 | I760811356160 484 | sVzoneid 485 | p221 486 | I1 487 | sVpodname 488 | p222 489 | VPod-A 490 | p223 491 | sVpercentused 492 | p224 493 | V20.35 494 | p225 495 | sVcapacitytotal 496 | p226 497 | I3738339639296 498 | sVtype 499 | p227 500 | I2 501 | sVzonename 502 | p228 503 | VDemo5 504 | p229 505 | sa(dp230 506 | Vcapacityused 507 | p231 508 | I15 509 | sVcapacitytotal 510 | p232 511 | I59 512 | sVpercentused 513 | p233 514 | V25.42 515 | p234 516 | sVzoneid 517 | p235 518 | I1 519 | sVtype 520 | p236 521 | I4 522 | sVzonename 523 | p237 524 | VDemo5 525 | p238 526 | sa(dp239 527 | Vpodid 528 | p240 529 | I-1 530 | sVcapacityused 531 | p241 532 | I283987935232 533 | sVzoneid 534 | p242 535 | I1 536 | sVpodname 537 | p243 538 | VAll 539 | p244 540 | sVpercentused 541 | p245 542 | V4.45 543 | p246 544 | sVcapacitytotal 545 | p247 546 | I6377167650816 547 | sVtype 548 | p248 549 | I3 550 | sVzonename 551 | p249 552 | VDemo5 553 | p250 554 | sa(dp251 555 | Vpodid 556 | p252 557 | I-1 558 | sVcapacityused 559 | p253 560 | I760811356160 561 | sVzoneid 562 | p254 563 | I1 564 | sVpodname 565 | p255 566 | VAll 567 | p256 568 | sVpercentused 569 | p257 570 | V20.35 571 | p258 572 | sVcapacitytotal 573 | p259 574 | I3738339639296 575 | sVtype 576 | p260 577 | I2 578 | sVzonename 579 | p261 580 | VDemo5 581 | p262 582 | sa(dp263 583 | Vpodid 584 | p264 585 | I1 586 | sVcapacityused 587 | p265 588 | I2 589 | sVzoneid 590 | p266 591 | I1 592 | sVpodname 593 | p267 594 | VPod-A 595 | p268 596 | sVpercentused 597 | p269 598 | V9.52 599 | p270 600 | sVcapacitytotal 601 | p271 602 | I21 603 | sVtype 604 | p272 605 | I5 606 | sVzonename 607 | p273 608 | VDemo5 609 | p274 610 | sa(dp275 611 | Vpodid 612 | p276 613 | I-1 614 | sVcapacityused 615 | p277 616 | I2 617 | sVzoneid 618 | p278 619 | I1 620 | sVpodname 621 | p279 622 | VAll 623 | p280 624 | sVpercentused 625 | p281 626 | V9.52 627 | p282 628 | sVcapacitytotal 629 | p283 630 | I21 631 | sVtype 632 | p284 633 | I5 634 | sVzonename 635 | p285 636 | VDemo5 637 | p286 638 | sa(dp287 639 | Vcapacityused 640 | p288 641 | I685896761344 642 | sVcapacitytotal 643 | p289 644 | I2638828011520 645 | sVpercentused 646 | p290 647 | V25.99 648 | p291 649 | sVzoneid 650 | p292 651 | I1 652 | sVtype 653 | p293 654 | I6 655 | sVzonename 656 | p294 657 | VDemo5 658 | p295 659 | sa(dp296 660 | Vpodid 661 | p297 662 | I1 663 | sVcapacityused 664 | p298 665 | I283987935232 666 | sVzoneid 667 | p299 668 | I1 669 | sVpodname 670 | p300 671 | VPod-A 672 | p301 673 | sVpercentused 674 | p302 675 | V4.45 676 | p303 677 | sVcapacitytotal 678 | p304 679 | I6377167650816 680 | sVtype 681 | p305 682 | I3 683 | sVzonename 684 | p306 685 | VDemo5 686 | p307 687 | sa(dp308 688 | Vpodid 689 | p309 690 | I-1 691 | sVcapacityused 692 | p310 693 | I13153337344 694 | sVzoneid 695 | p311 696 | I1 697 | sVpodname 698 | p312 699 | VAll 700 | p313 701 | sVpercentused 702 | p314 703 | V40.62 704 | p315 705 | sVcapacitytotal 706 | p316 707 | I32379580416 708 | sVtype 709 | p317 710 | I0 711 | sVzonename 712 | p318 713 | VDemo5 714 | p319 715 | sassS'listpodsresponse' 716 | p320 717 | (dp321 718 | Vcount 719 | p322 720 | I1 721 | sVpod 722 | p323 723 | (lp324 724 | (dp325 725 | Vendip 726 | p326 727 | V10.208.37.120 728 | p327 729 | sVname 730 | p328 731 | VPod-A 732 | p329 733 | sVstartip 734 | p330 735 | V10.208.37.100 736 | p331 737 | sVallocationstate 738 | p332 739 | VEnabled 740 | p333 741 | sVzoneid 742 | p334 743 | I1 744 | sVnetmask 745 | p335 746 | V255.255.255.128 747 | p336 748 | sVid 749 | p337 750 | I1 751 | sVgateway 752 | p338 753 | V10.208.37.1 754 | p339 755 | sVzonename 756 | p340 757 | VDemo5 758 | p341 759 | sass. -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/tests/data/listalertsresponse.json: -------------------------------------------------------------------------------- 1 | { "listalertsresponse" : { "count":20 ,"alert" : [ {"id":20,"type":1,"description":"System Alert: Low Unallocated CPU in pod Pod-A of availablity zone Demo5","sent":"2011-10-31T06:35:29-0700"}, {"id":19,"type":1,"description":"System Alert: Low Unallocated CPU in pod Pod-A of availablity zone Demo5","sent":"2011-10-31T06:30:29-0700"}, {"id":18,"type":7,"description":"Failed to deploy Vm with Id: 53","sent":"2011-10-26T12:20:51-0700"}, {"id":17,"type":7,"description":"Failed to deploy Vm with Id: 52","sent":"2011-10-26T12:19:19-0700"}, {"id":16,"type":7,"description":"Failed to deploy Vm with Id: 49","sent":"2011-10-25T13:21:49-0700"}, {"id":15,"type":7,"description":"Failed to deploy Vm with Id: 47","sent":"2011-10-25T13:14:56-0700"}, {"id":14,"type":7,"description":"Failed to deploy Vm with Id: 41","sent":"2011-10-21T06:30:25-0700"}, {"id":13,"type":13,"description":"Management server node 10.208.32.205 is up","sent":"2011-10-19T11:20:02-0700"}, {"id":12,"type":13,"description":"Management server node 10.208.32.205 is up","sent":"2011-10-19T10:48:38-0700"}, {"id":11,"type":13,"description":"Management server node 10.208.32.205 is up","sent":"2011-10-19T10:46:50-0700"}, {"id":10,"type":13,"description":"Management server node 10.208.32.205 is up","sent":"2011-10-18T18:05:03-0700"}, {"id":7,"type":6,"description":"Host is down, name: demo5-xen (id:1), availability zone: Demo5, pod: Pod-A","sent":"2011-10-17T22:02:39-0700"}, {"id":8,"type":7,"description":"Unable to restart s-1-Demo5 which was running on host name: demo5-xen(id:1), availability zone: Demo5, pod: Pod-A","sent":"2011-10-17T22:02:39-0700"}, {"id":9,"type":9,"description":"Unable to restart v-2-Demo5 which was running on host name: demo5-xen(id:1), availability zone: Demo5, pod: Pod-A","sent":"2011-10-17T22:02:39-0700"}, {"id":6,"type":13,"description":"Management server node 10.208.32.205 is up","sent":"2011-10-17T21:49:14-0700"}, {"id":5,"type":12,"description":"No usage server process running","sent":"2011-10-17T21:17:18-0700"}, {"id":4,"type":12,"description":"No usage server process running","sent":"2011-10-17T21:07:18-0700"}, {"id":3,"type":13,"description":"Management server node 10.208.32.205 is up","sent":"2011-10-17T20:07:21-0700"}, {"id":2,"type":13,"description":"Management server node 10.208.32.205 is up","sent":"2011-10-17T19:56:27-0700"}, {"id":1,"type":13,"description":"Management network CIDR is not configured originally. Set it default to 10.208.32.0/24","sent":"2011-10-17T19:56:24-0700"} ] } } -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/tests/data/listcapacityresponse.json: -------------------------------------------------------------------------------- 1 | { "listcapacityresponse" : { "count":12 ,"capacity" : [ {"type":1,"zoneid":1,"zonename":"Demo5","podid":-1,"podname":"All","capacityused":17000,"capacitytotal":17600,"percentused":"96.59"}, {"type":0,"zoneid":1,"zonename":"Demo5","podid":1,"podname":"Pod-A","capacityused":13421772800,"capacitytotal":32379580416,"percentused":"41.45"}, {"type":1,"zoneid":1,"zonename":"Demo5","podid":1,"podname":"Pod-A","capacityused":17000,"capacitytotal":17600,"percentused":"96.59"}, {"type":2,"zoneid":1,"zonename":"Demo5","podid":1,"podname":"Pod-A","capacityused":783219687424,"capacitytotal":3738339639296,"percentused":"20.95"}, {"type":4,"zoneid":1,"zonename":"Demo5","capacityused":16,"capacitytotal":59,"percentused":"27.12"}, {"type":3,"zoneid":1,"zonename":"Demo5","podid":-1,"podname":"All","capacityused":292577869824,"capacitytotal":6377167650816,"percentused":"4.59"}, {"type":2,"zoneid":1,"zonename":"Demo5","podid":-1,"podname":"All","capacityused":783219687424,"capacitytotal":3738339639296,"percentused":"20.95"}, {"type":5,"zoneid":1,"zonename":"Demo5","podid":1,"podname":"Pod-A","capacityused":2,"capacitytotal":21,"percentused":"9.52"}, {"type":5,"zoneid":1,"zonename":"Demo5","podid":-1,"podname":"All","capacityused":2,"capacitytotal":21,"percentused":"9.52"}, {"type":6,"zoneid":1,"zonename":"Demo5","capacityused":697750978560,"capacitytotal":2638828011520,"percentused":"26.44"}, {"type":3,"zoneid":1,"zonename":"Demo5","podid":1,"podname":"Pod-A","capacityused":292577869824,"capacitytotal":6377167650816,"percentused":"4.59"}, {"type":0,"zoneid":1,"zonename":"Demo5","podid":-1,"podname":"All","capacityused":13421772800,"capacitytotal":32379580416,"percentused":"41.45"} ] } } -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/tests/data/listclustersresponse.json: -------------------------------------------------------------------------------- 1 | { "listclustersresponse" : { "count":3 ,"cluster" : [ {"id":1,"name":"XenCluster1-D5","podid":1,"podname":"Pod-A","zoneid":1,"zonename":"Demo5","hypervisortype":"XenServer","clustertype":"CloudManaged","allocationstate":"Enabled","managedstate":"Managed"}, {"id":2,"name":"baremetal delete me","podid":1,"podname":"Pod-A","zoneid":1,"zonename":"Demo5","hypervisortype":"BareMetal","clustertype":"CloudManaged","allocationstate":"Enabled","managedstate":"Managed"}, {"id":3,"name":"kevin test","podid":1,"podname":"Pod-A","zoneid":1,"zonename":"Demo5","hypervisortype":"BareMetal","clustertype":"CloudManaged","allocationstate":"Enabled","managedstate":"Managed"} ] } } -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/tests/data/listconfigurationsresponse.json: -------------------------------------------------------------------------------- 1 | { "listconfigurationsresponse" : { "count":1 ,"configuration" : [ {"category":"Advanced","name":"default.page.size","value":"500","description":"Default page size for API list* commands"} ] } } -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/tests/data/listhostsresponse.json: -------------------------------------------------------------------------------- 1 | { "listhostsresponse" : { "count":5 ,"host" : [ {"id":1,"name":"demo5-xen","state":"Up","disconnected":"2011-10-17T22:02:39-0700","type":"Routing","ipaddress":"10.208.37.11","zoneid":1,"zonename":"Demo5","podid":1,"podname":"Pod-A","version":"2.2.12.20110927185324","hypervisor":"XenServer","cpunumber":4,"cpuspeed":2200,"cpuallocated":"73.86%","cpuused":"0.21%","cpuwithoverprovisioning":"8800.0","networkkbsread":0,"networkkbswrite":0,"memorytotal":16189790400,"memoryallocated":7516192768,"memoryused":7516192768,"capabilities":"xen-3.0-x86_64 , xen-3.0-x86_32p , hvm-3.0-x86_32 , hvm-3.0-x86_32p , hvm-3.0-x86_64","lastpinged":"1970-01-15T13:48:52-0800","managementserverid":257544418526661,"clusterid":1,"clustername":"XenCluster1-D5","clustertype":"CloudManaged","islocalstorageactive":false,"created":"2011-10-17T21:19:45-0700","events":"Ping; PrepareUnmanaged; PingTimeout; AgentDisconnected; HypervisorVersionChanged; StartAgentRebalance; HostDown; ShutdownRequested; MaintenanceRequested; ManagementServerDown; AgentConnected","hosttags":"","hasEnoughCapacity":false,"allocationstate":"Enabled"}, {"id":2,"name":"nfs://10.208.32.25/vol/export/demo5/ss","state":"Alert","disconnected":"2011-10-17T21:23:31-0700","type":"SecondaryStorage","ipaddress":"nfs","zoneid":1,"zonename":"Demo5","version":"2.2.12.20110927185324","hypervisor":"None","lastpinged":"1970-01-15T13:46:39-0800","islocalstorageactive":false,"created":"2011-10-17T21:23:31-0700","events":"Ping; AgentDisconnected; Remove; MaintenanceRequested; ManagementServerDown; AgentConnected","hasEnoughCapacity":false,"allocationstate":"Enabled"}, {"id":3,"name":"s-1-Demo5","state":"Up","disconnected":"2011-10-17T22:09:08-0700","type":"SecondaryStorageVM","ipaddress":"10.208.37.105","zoneid":1,"zonename":"Demo5","podid":1,"podname":"Pod-A","version":"2.2.12.20110927185324","lastpinged":"1970-01-15T13:48:53-0800","managementserverid":257544418526661,"islocalstorageactive":false,"created":"2011-10-17T21:30:13-0700","events":"Ping; PrepareUnmanaged; PingTimeout; AgentDisconnected; HypervisorVersionChanged; StartAgentRebalance; HostDown; ShutdownRequested; MaintenanceRequested; ManagementServerDown; AgentConnected","hasEnoughCapacity":false,"allocationstate":"Enabled"}, {"id":4,"name":"v-2-Demo5","state":"Up","type":"ConsoleProxy","ipaddress":"10.208.37.116","zoneid":1,"zonename":"Demo5","podid":1,"podname":"Pod-A","version":"2.2.12.20110927185324","lastpinged":"1970-01-15T13:48:53-0800","managementserverid":257544418526661,"islocalstorageactive":false,"created":"2011-10-17T21:31:07-0700","events":"Ping; PrepareUnmanaged; PingTimeout; AgentDisconnected; HypervisorVersionChanged; StartAgentRebalance; HostDown; ShutdownRequested; MaintenanceRequested; ManagementServerDown; AgentConnected","hasEnoughCapacity":false,"allocationstate":"Enabled"}, {"id":5,"name":"demo5-xen2","state":"Up","type":"Routing","ipaddress":"10.208.37.12","zoneid":1,"zonename":"Demo5","podid":1,"podname":"Pod-A","version":"2.2.12.20110927185324","hypervisor":"XenServer","cpunumber":4,"cpuspeed":2200,"cpuallocated":"62.5%","cpuused":"0.03%","cpuwithoverprovisioning":"8800.0","networkkbsread":0,"networkkbswrite":0,"memorytotal":16189790400,"memoryallocated":5905580032,"memoryused":5905580032,"capabilities":"xen-3.0-x86_64 , xen-3.0-x86_32p , hvm-3.0-x86_32 , hvm-3.0-x86_32p , hvm-3.0-x86_64","lastpinged":"1970-01-15T13:48:52-0800","managementserverid":257544418526661,"clusterid":1,"clustername":"XenCluster1-D5","clustertype":"CloudManaged","islocalstorageactive":false,"created":"2011-10-17T22:12:21-0700","events":"Ping; PrepareUnmanaged; PingTimeout; AgentDisconnected; HypervisorVersionChanged; StartAgentRebalance; HostDown; ShutdownRequested; MaintenanceRequested; ManagementServerDown; AgentConnected","hosttags":"","hasEnoughCapacity":false,"allocationstate":"Enabled"} ] } } -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/tests/data/listpodsresponse.json: -------------------------------------------------------------------------------- 1 | { "listpodsresponse" : { "count":1 ,"pod" : [ {"id":1,"name":"Pod-A","zoneid":1,"zonename":"Demo5","gateway":"10.208.37.1","netmask":"255.255.255.128","startip":"10.208.37.100","endip":"10.208.37.120","allocationstate":"Enabled"} ] } } -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/tests/data/listsystemvmsresponse.json: -------------------------------------------------------------------------------- 1 | {'listsystemvmsresponse': {u'count': 4, 2 | u'systemvm': [{u'created': u'2011-10-17T21:23:48-0700', 3 | u'dns1': u'72.52.126.11', 4 | u'gateway': u'72.52.126.1', 5 | u'hostid': 1, 6 | u'hostname': u'demo5-xen', 7 | u'id': 1, 8 | u'linklocalip': u'169.254.1.112', 9 | u'linklocalmacaddress': u'0e:00:a9:fe:01:70', 10 | u'linklocalnetmask': u'255.255.0.0', 11 | u'name': u's-1-Demo5', 12 | u'podid': 1, 13 | u'privateip': u'10.208.37.105', 14 | u'privatemacaddress': u'06:f3:36:00:00:39', 15 | u'privatenetmask': u'255.255.255.128', 16 | u'publicip': u'72.52.126.100', 17 | u'publicmacaddress': u'06:90:98:00:00:20', 18 | u'publicnetmask': u'255.255.255.128', 19 | u'state': u'Destroyed', 20 | u'systemvmtype': u'secondarystoragevm', 21 | u'templateid': 1, 22 | u'zoneid': 1, 23 | u'zonename': u'Demo5'}, 24 | {u'activeviewersessions': 2, 25 | u'created': u'2011-10-17T21:23:48-0700', 26 | u'dns1': u'72.52.126.11', 27 | u'gateway': u'72.52.126.1', 28 | u'hostid': 1, 29 | u'hostname': u'demo5-xen', 30 | u'id': 2, 31 | u'linklocalip': u'169.254.1.66', 32 | u'linklocalmacaddress': u'0e:00:a9:fe:01:42', 33 | u'linklocalnetmask': u'255.255.0.0', 34 | u'name': u'v-2-Demo5', 35 | u'podid': 1, 36 | u'privateip': u'10.208.37.116', 37 | u'privatemacaddress': u'06:8d:44:00:00:44', 38 | u'privatenetmask': u'255.255.255.128', 39 | u'publicip': u'72.52.126.98', 40 | u'publicmacaddress': u'06:dd:58:00:00:1e', 41 | u'publicnetmask': u'255.255.255.128', 42 | u'state': u'Destroyed', 43 | u'systemvmtype': u'consoleproxy', 44 | u'templateid': 1, 45 | u'zoneid': 1, 46 | u'zonename': u'Demo5'}, 47 | {u'created': u'2011-11-08T21:26:25-0800', 48 | u'dns1': u'72.52.126.11', 49 | u'gateway': u'72.52.126.1', 50 | u'hostid': 7, 51 | u'hostname': u'xenserver-330-2', 52 | u'id': 156, 53 | u'linklocalip': u'169.254.1.9', 54 | u'linklocalmacaddress': u'0e:00:a9:fe:01:09', 55 | u'linklocalnetmask': u'255.255.0.0', 56 | u'name': u's-156-Demo5', 57 | u'podid': 2, 58 | u'privateip': u'10.208.33.14', 59 | u'privatemacaddress': u'06:b1:84:00:00:b4', 60 | u'privatenetmask': u'255.255.255.128', 61 | u'publicip': u'72.52.126.96', 62 | u'publicmacaddress': u'06:5b:46:00:00:1c', 63 | u'publicnetmask': u'255.255.255.128', 64 | u'state': u'Running', 65 | u'systemvmtype': u'secondarystoragevm', 66 | u'templateid': 1, 67 | u'zoneid': 1, 68 | u'zonename': u'Demo5'}, 69 | {u'activeviewersessions': 0, 70 | u'created': u'2011-11-08T21:26:55-0800', 71 | u'dns1': u'72.52.126.11', 72 | u'gateway': u'72.52.126.1', 73 | u'hostid': 6, 74 | u'hostname': u'xenserver-330-1', 75 | u'id': 157, 76 | u'linklocalip': u'169.254.0.158', 77 | u'linklocalmacaddress': u'0e:00:a9:fe:00:9e', 78 | u'linklocalnetmask': u'255.255.0.0', 79 | u'name': u'v-157-Demo5', 80 | u'podid': 2, 81 | u'privateip': u'10.208.33.23', 82 | u'privatemacaddress': u'06:18:86:00:00:bd', 83 | u'privatenetmask': u'255.255.255.128', 84 | u'publicip': u'72.52.126.116', 85 | u'publicmacaddress': u'06:b2:aa:00:00:30', 86 | u'publicnetmask': u'255.255.255.128', 87 | u'state': u'Running', 88 | u'systemvmtype': u'consoleproxy', 89 | u'templateid': 1, 90 | u'zoneid': 1, 91 | u'zonename': u'Demo5'}]}} 92 | -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/tests/data/listzonesresponse.json: -------------------------------------------------------------------------------- 1 | { "listzonesresponse" : { "count":1 ,"zone" : [ {"id":1,"name":"Demo5","dns1":"72.52.126.11","internaldns1":"72.52.126.12","vlan":"1000-1200","guestcidraddress":"10.1.1.0/24","networktype":"Advanced","securitygroupsenabled":false,"allocationstate":"Enabled","zonetoken":"f0c6542e-7a1a-39b3-8c92-1a1c67cede0b","dhcpprovider":"VirtualRouter"} ] } } -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/tests/testAPI.py: -------------------------------------------------------------------------------- 1 | ########################################################################### 2 | # 3 | # This program is part of Zenoss Core, an open source monitoring platform. 4 | # Copyright (C) 2011, Zenoss Inc. 5 | # 6 | # This program is free software; you can redistribute it and/or modify it 7 | # under the terms of the GNU General Public License version 2 or (at your 8 | # option) any later version as published by the Free Software Foundation. 9 | # 10 | # For complete information please visit: http://www.zenoss.com/oss/ 11 | # 12 | ########################################################################### 13 | 14 | import re 15 | 16 | import logging 17 | log = logging.getLogger('zen.CloudStack') 18 | 19 | from Products.Five import zcml 20 | 21 | from Products.ZenTestCase.BaseTestCase import BaseTestCase 22 | 23 | 24 | class TestAPI(BaseTestCase): 25 | def afterSetUp(self): 26 | super(TestAPI, self).afterSetUp() 27 | 28 | # Required to prevent erroring out when trying to define viewlets in 29 | # ../browser/configure.zcml. 30 | import zope.viewlet 31 | zcml.load_config('meta.zcml', zope.viewlet) 32 | 33 | import ZenPacks.zenoss.CloudStack 34 | zcml.load_config('configure.zcml', ZenPacks.zenoss.CloudStack) 35 | 36 | # def testRouterAndFacade(self): 37 | # from ZenPacks.zenoss.CloudStack.routers import CloudStackRouter 38 | # router = CloudStackRouter(self.dmd) 39 | # 40 | # # Test success case. 41 | # r = router.add_cloudstack('x', 'http://cloudstack.example.com/', 'x', 'x') 42 | # self.assertTrue(r.data['success']) 43 | # 44 | # self.dmd.Devices.createInstance('cloudstack.example.com') 45 | # 46 | # # Test failure case. Device already exists. 47 | # r1 = router.add_cloudstack('x', 'http://cloudstack.example.com/', 'x', 'x') 48 | # self.assertTrue(r.data['success']) 49 | # self.assertEqual( 50 | # r1.data['msg'], 51 | # 'A device named cloudstack.example.com already exists.') 52 | 53 | 54 | def test_suite(): 55 | from unittest import TestSuite, makeSuite 56 | suite = TestSuite() 57 | suite.addTest(makeSuite(TestAPI)) 58 | return suite 59 | -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/tests/testModel.py: -------------------------------------------------------------------------------- 1 | ########################################################################### 2 | # 3 | # This program is part of Zenoss Core, an open source monitoring platform. 4 | # Copyright (C) 2011, Zenoss Inc. 5 | # 6 | # This program is free software; you can redistribute it and/or modify it 7 | # under the terms of the GNU General Public License version 2 or (at your 8 | # option) any later version as published by the Free Software Foundation. 9 | # 10 | # For complete information please visit: http://www.zenoss.com/oss/ 11 | # 12 | ########################################################################### 13 | 14 | import logging 15 | log = logging.getLogger('zen.CloudStack') 16 | 17 | from Products.Five import zcml 18 | 19 | from Products.DataCollector.ApplyDataMap import ApplyDataMap 20 | from Products.ZenModel import ZVersion 21 | from Products.ZenTestCase.BaseTestCase import BaseTestCase 22 | from Products.Zuul.interfaces.info import IInfo 23 | 24 | from ZenPacks.zenoss.CloudStack.modeler.plugins.zenoss.CloudStack \ 25 | import CloudStack as CloudStackModeler 26 | 27 | from ZenPacks.zenoss.CloudStack.tests.utils import loadPickle 28 | 29 | 30 | CLOUDSTACK_ICON = '/++resource++cloudstack/img/cloudstack.png' 31 | 32 | 33 | class MockJar(object): 34 | """Mock object for x._p_jar. 35 | 36 | Used to trick ApplyDataMap into not aborting transactions after adding 37 | non-persistent objects. Without doing this, all sub-components will cause 38 | ugly tracebacks in modeling tests. 39 | 40 | """ 41 | 42 | def sync(self): 43 | pass 44 | 45 | 46 | class TestModel(BaseTestCase): 47 | def afterSetUp(self): 48 | super(TestModel, self).afterSetUp() 49 | 50 | dc = self.dmd.Devices.createOrganizer('/CloudStack') 51 | dc.setZenProperty('zPythonClass', 'ZenPacks.zenoss.CloudStack.Cloud') 52 | 53 | self.d = dc.createInstance('zenoss.CloudStack.testDevice') 54 | 55 | if not ZVersion.VERSION.startswith('3.'): 56 | self.d.dmd._p_jar = MockJar() 57 | 58 | self.applyDataMap = ApplyDataMap()._applyDataMap 59 | 60 | # Required to prevent erroring out when trying to define viewlets in 61 | # ../browser/configure.zcml. 62 | import zope.viewlet 63 | zcml.load_config('meta.zcml', zope.viewlet) 64 | 65 | import ZenPacks.zenoss.CloudStack 66 | zcml.load_config('configure.zcml', ZenPacks.zenoss.CloudStack) 67 | 68 | def _loadZenossData(self): 69 | if hasattr(self, '_loaded'): 70 | return 71 | 72 | modeler = CloudStackModeler() 73 | modeler_results = loadPickle('cloudstack_results.pickle') 74 | 75 | for data_map in modeler.process(self.d, modeler_results, log): 76 | self.applyDataMap(self.d, data_map) 77 | 78 | self._loaded = True 79 | 80 | def testCloud(self): 81 | self._loadZenossData() 82 | 83 | info = IInfo(self.d) 84 | self.assertEquals(info.zone_count, 1) 85 | self.assertEquals(info.pod_count, 2) 86 | self.assertEquals(info.cluster_count, 2) 87 | self.assertEquals(info.host_count, 6) 88 | 89 | def testZone(self): 90 | self._loadZenossData() 91 | 92 | zone = self.d.zones._getOb('zone1') 93 | self.assertEquals(zone.device().id, 'zenoss.CloudStack.testDevice') 94 | 95 | info = IInfo(zone) 96 | self.assertEquals(info.name, 'Demo5') 97 | self.assertEquals(info.icon, CLOUDSTACK_ICON) 98 | self.assertEquals(info.cloudstack_id, 1) 99 | self.assertEquals(info.allocation_state, 'Enabled') 100 | self.assertEquals(info.guest_cidr_address, '10.1.1.0/24') 101 | self.assertEquals(info.dhcp_provider, 'VirtualRouter') 102 | self.assertEquals(info.public_dns, '72.52.126.11, ') 103 | self.assertEquals(info.internal_dns, '72.52.126.12, 72.52.126.12') 104 | self.assertEquals(info.network_type, 'Advanced') 105 | self.assertEquals(info.security_groups_enabled, False) 106 | self.assertEquals(info.vlan, '1000-1200') 107 | self.assertEquals(info.zone_token, 'f0c6542e-7a1a-39b3-8c92-1a1c67cede0b') 108 | self.assertEquals(info.pod_count, 2) 109 | self.assertEquals(info.cluster_count, 2) 110 | self.assertEquals(info.host_count, 6) 111 | 112 | def testPod(self): 113 | self._loadZenossData() 114 | 115 | zone = self.d.zones._getOb('zone1') 116 | pod = zone.pods._getOb('pod1') 117 | 118 | self.assertEquals(pod.device().id, 'zenoss.CloudStack.testDevice') 119 | 120 | info = IInfo(pod) 121 | self.assertEquals(info.name, 'Pod-A') 122 | self.assertEquals(info.icon, CLOUDSTACK_ICON) 123 | self.assertEquals(info.cloudstack_id, 1) 124 | self.assertEquals(info.allocation_state, 'Enabled') 125 | self.assertEquals(info.ip_range, '10.208.37.100 - 10.208.37.120') 126 | self.assertEquals(info.netmask, '255.255.255.128') 127 | self.assertEquals(info.gateway, '10.208.37.1') 128 | self.assertEquals(info.zone.id, 'zone1') 129 | self.assertEquals(info.cluster_count, 1) 130 | self.assertEquals(info.host_count, 3) 131 | 132 | def testCluster(self): 133 | self._loadZenossData() 134 | 135 | zone = self.d.zones._getOb('zone1') 136 | pod = zone.pods._getOb('pod1') 137 | cluster = pod.clusters._getOb('cluster1') 138 | 139 | self.assertEquals(cluster.device().id, 'zenoss.CloudStack.testDevice') 140 | 141 | info = IInfo(cluster) 142 | self.assertEquals(info.name, 'XenCluster1-D5') 143 | self.assertEquals(info.icon, CLOUDSTACK_ICON) 144 | self.assertEquals(info.cloudstack_id, 1) 145 | self.assertEquals(info.allocation_state, 'Enabled') 146 | self.assertEquals(info.cluster_type, 'CloudManaged') 147 | self.assertEquals(info.hypervisor_type, 'XenServer') 148 | self.assertEquals(info.managed_state, 'Managed') 149 | self.assertEquals(info.zone.id, 'zone1') 150 | self.assertEquals(info.pod.id, 'pod1') 151 | self.assertEquals(info.host_count, 3) 152 | 153 | def testHost(self): 154 | self._loadZenossData() 155 | 156 | zone = self.d.zones._getOb('zone1') 157 | pod = zone.pods._getOb('pod1') 158 | cluster = pod.clusters._getOb('cluster1') 159 | host = cluster.hosts._getOb('host1') 160 | 161 | self.assertEquals(host.device().id, 'zenoss.CloudStack.testDevice') 162 | 163 | info = IInfo(host) 164 | self.assertEquals(info.name, 'demo5-xen') 165 | self.assertEquals(info.icon, CLOUDSTACK_ICON) 166 | self.assertEquals(info.cloudstack_id, 1) 167 | self.assertEquals(info.allocation_state, 'Enabled') 168 | self.assertEquals(info.host_type, 'Routing') 169 | self.assertEquals(info.hypervisor, 'XenServer') 170 | self.assertEquals(info.host_version, '2.2.13.20111117191758') 171 | self.assertEquals(info.capabilities, 'xen-3.0-x86_64 , xen-3.0-x86_32p , hvm-3.0-x86_32 , hvm-3.0-x86_32p , hvm-3.0-x86_64') 172 | self.assertEquals(info.host_state, 'Up') 173 | self.assertEquals(info.created, '2011-10-17T21:19:45-0700') 174 | self.assertEquals(info.host_tags, '') 175 | self.assertEquals(info.ip_address, '10.208.37.11') 176 | self.assertEquals(info.host_events, 'ShutdownRequested; AgentDisconnected; AgentConnected; HypervisorVersionChanged; PrepareUnmanaged; HostDown; PingTimeout; ManagementServerDown; StartAgentRebalance; Ping; MaintenanceRequested') 177 | self.assertEquals(info.local_storage_active, False) 178 | self.assertEquals(info.management_server_id, 257544418526661) 179 | self.assertEquals(info.zone.id, 'zone1') 180 | self.assertEquals(info.pod.id, 'pod1') 181 | self.assertEquals(info.cluster.id, 'cluster1') 182 | 183 | def test_getManagedDevice(self): 184 | self._loadZenossData() 185 | 186 | host_device1 = self.dmd.Devices.createInstance('host_device1') 187 | host_device1.setManageIp('10.208.37.11') 188 | host_device1.setPerformanceMonitor('localhost') 189 | 190 | host_device2 = self.dmd.Devices.createInstance('host_device2') 191 | host_device2.setManageIp('12.34.56.78') 192 | host_device2.setPerformanceMonitor('localhost') 193 | 194 | from Products.ZenModel.IpInterface import manage_addIpInterface 195 | manage_addIpInterface(host_device2.os.interfaces, 'eth0', False) 196 | eth0 = host_device2.os.interfaces._getOb('eth0') 197 | eth0.setIpAddresses(['10.208.37.12/24']) 198 | 199 | zone = self.d.zones._getOb('zone1') 200 | pod = zone.pods._getOb('pod1') 201 | cluster = pod.clusters._getOb('cluster1') 202 | 203 | # Test finding host device by manageIp. 204 | info1 = IInfo(cluster.hosts._getOb('host1')) 205 | self.assertEquals(info1.managed_device.id, 'host_device1') 206 | 207 | # Test finding host by interface IP. 208 | info2 = IInfo(cluster.hosts._getOb('host5')) 209 | self.assertEquals(info2.managed_device.id, 'host_device2') 210 | 211 | def testMissingHostsResponse(self): 212 | modeler = CloudStackModeler() 213 | modeler_results = loadPickle('cloudstack_results_missingHosts.pickle') 214 | 215 | maps = modeler.process(self.d, modeler_results, log) 216 | self.assertNotEquals(maps, None) 217 | 218 | def testNoZonesResponse(self): 219 | modeler = CloudStackModeler() 220 | modeler_results = loadPickle('cloudstack_results_noZones.pickle') 221 | 222 | maps = modeler.process(self.d, modeler_results, log) 223 | self.assertEquals(len(maps), 4) 224 | self.assertEquals(maps[0].relname, 'zones') 225 | self.assertEquals(maps[1].relname, 'pods') 226 | self.assertEquals(maps[2].relname, 'clusters') 227 | self.assertEquals(maps[3].relname, 'hosts') 228 | self.assertEquals(len(maps[0].maps), 0) 229 | 230 | 231 | def test_suite(): 232 | from unittest import TestSuite, makeSuite 233 | suite = TestSuite() 234 | suite.addTest(makeSuite(TestModel)) 235 | return suite 236 | -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/tests/testObjects.py: -------------------------------------------------------------------------------- 1 | ########################################################################### 2 | # 3 | # This program is part of Zenoss Core, an open source monitoring platform. 4 | # Copyright (C) 2011 TELUS 5 | # 6 | ########################################################################### 7 | 8 | import re 9 | 10 | import logging 11 | log = logging.getLogger('zen.CloudStack') 12 | 13 | from zope.component import getUtility 14 | 15 | import sys 16 | import os.path 17 | 18 | from Products.Five import zcml 19 | from Products.ZenModel.interfaces import IDeviceLoader 20 | from Products.ZenTestCase.BaseTestCase import BaseTestCase 21 | 22 | 23 | ZENPACK_DEPENDENCIES = ( 24 | 'ZenPacks.zenoss.CloudStack', 25 | ) 26 | 27 | DEVICECLASS_DEPENDENCIES = tuple() 28 | 29 | EVENTCLASS_DEPENDENCIES = ( 30 | '/App', 31 | '/Capacity', 32 | '/Perf', 33 | '/Status', 34 | ) 35 | 36 | REPORTCLASS_DEPENDENCIES = tuple() 37 | 38 | 39 | class TestObjects(BaseTestCase): 40 | """ 41 | Test suite containing test for objects that should be installed from this 42 | ZenPack's objects.xml file. 43 | 44 | WARNING: This test suite is slow because its afterSetup loads a lot of 45 | objects. 46 | """ 47 | 48 | def afterSetUp(self): 49 | super(TestObjects, self).afterSetUp() 50 | 51 | map(self.dmd.Devices.createOrganizer, (DEVICECLASS_DEPENDENCIES)) 52 | map(self.dmd.Events.createOrganizer, (EVENTCLASS_DEPENDENCIES)) 53 | map(self.dmd.Reports.createOrganizer, (REPORTCLASS_DEPENDENCIES)) 54 | 55 | self.dmd.REQUEST = None 56 | 57 | from Products.ZenRelations.ImportRM import NoLoginImportRM 58 | im = NoLoginImportRM(self.app) 59 | 60 | for zenpack in ZENPACK_DEPENDENCIES: 61 | __import__(zenpack) 62 | zp_module = sys.modules[zenpack] 63 | 64 | objects_file = '%s/objects/objects.xml' % zp_module.__path__[0] 65 | 66 | if os.path.isfile(objects_file): 67 | log.info('Loading objects for %s.', zenpack) 68 | im.loadObjectFromXML(objects_file) 69 | 70 | # Required to prevent erroring out when trying to define viewlets in 71 | # ../browser/configure.zcml. 72 | import zope.viewlet 73 | zcml.load_config('meta.zcml', zope.viewlet) 74 | 75 | import ZenPacks.zenoss.CloudStack 76 | zcml.load_config('configure.zcml', ZenPacks.zenoss.CloudStack) 77 | 78 | def testConfigurationProperties(self): 79 | """Verify all configuration properties are set properly.""" 80 | dc = self.dmd.Devices.CloudStack 81 | self.assertEqual(dc.zPingMonitorIgnore, True) 82 | self.assertEqual(dc.zSnmpMonitorIgnore, True) 83 | self.assertEqual(dc.zWmiMonitorIgnore, True) 84 | self.assertEqual(dc.zCollectorPlugins, ['zenoss.CloudStack']) 85 | self.assertEqual(dc.zDeviceTemplates, ['CloudStackCloud']) 86 | self.assertEqual(dc.zPythonClass, 'ZenPacks.zenoss.CloudStack.Cloud') 87 | self.assertEqual(dc.zIcon, '/++resource++cloudstack/img/cloudstack.png') 88 | self.assertEqual(dc.zCommandCommandTimeout, 300.0) 89 | 90 | def testDeviceLoader(self): 91 | device_loader = getUtility(IDeviceLoader, 'cloudstack', None) 92 | job = device_loader().load_device( 93 | self.dmd, 'x', 'http://cloudstack.example.com/', 'x', 'x') 94 | 95 | self.assertTrue(job) 96 | 97 | def testTemplates(self): 98 | """Verify all templates are configured properly. 99 | 100 | 1. Verify all DERIVE type datapoints have an rrdmin of 0. 101 | 2. Verify all percentage datapoints have rrdmin of 0 and rrdmax of 100. 102 | """ 103 | template_names = ( 104 | 'CloudStackCloud', 'CloudStackZone', 'CloudStackPod', 105 | 'CloudStackCluster', 'CloudStackHost', 106 | ) 107 | 108 | for t_name in template_names: 109 | t = self.dmd.Devices.CloudStack.rrdTemplates._getOb(t_name) 110 | for ds in t.datasources(): 111 | for dp in ds.datapoints(): 112 | if dp.rrdtype == 'DERIVE': 113 | self.assertEqual(int(dp.rrdmin), 0) 114 | 115 | # Lower-bound percentages at 0. No upper-bound to allow for 116 | # over-provisioning. 117 | elif dp.id.lower().endswith('percent'): 118 | self.assertEqual(int(dp.rrdmin), 0) 119 | self.assertEqual(dp.rrdmax, None) 120 | 121 | 122 | def test_suite(): 123 | from unittest import TestSuite, makeSuite 124 | suite = TestSuite() 125 | suite.addTest(makeSuite(TestObjects)) 126 | return suite 127 | -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/tests/testTXCloudStack.py: -------------------------------------------------------------------------------- 1 | ########################################################################### 2 | # 3 | # This program is part of Zenoss Core, an open source monitoring platform. 4 | # Copyright (C) 2011, Zenoss Inc. 5 | # 6 | # This program is free software; you can redistribute it and/or modify it 7 | # under the terms of the GNU General Public License version 2 or (at your 8 | # option) any later version as published by the Free Software Foundation. 9 | # 10 | # For complete information please visit: http://www.zenoss.com/oss/ 11 | # 12 | ########################################################################### 13 | 14 | import logging 15 | log = logging.getLogger('zen.CloudStack') 16 | 17 | from twisted.internet import reactor 18 | import twisted.web.client 19 | 20 | from Products.ZenTestCase.BaseTestCase import BaseTestCase 21 | 22 | from ZenPacks.zenoss.CloudStack.tests.utils import mockGetPage 23 | 24 | # Imported or side effect of adding ZenPack's lib directory to sys.path. 25 | import ZenPacks.zenoss.CloudStack.locallibs 26 | 27 | # Requires that locallibs first be imported. 28 | import txcloudstack 29 | 30 | 31 | class TestTXCloudStack(BaseTestCase): 32 | """Tests for the txcloudstack module. 33 | 34 | No tests are currently implemented in here because there seems to be some 35 | problem running a reactor in Zope unit tests. 36 | """ 37 | 38 | def afterSetUp(self): 39 | super(TestTXCloudStack, self).afterSetUp() 40 | 41 | self.client = txcloudstack.Client( 42 | 'http://cloudstack.example.com/', 'x', 'x') 43 | 44 | def test_listConfigurations(self): 45 | pass 46 | 47 | def test_listZones(self): 48 | # def _callback(result): 49 | # if reactor.running: 50 | # reactor.stop() 51 | 52 | # response = result.get('listzonesresponse', None) 53 | # self.assertTrue(isinstance(response, dict)) 54 | # self.assertEqual(response['count'], 1) 55 | # self.assertEqual(len(response['zone']), 1) 56 | 57 | # twisted.web.client.getPage = mockGetPage 58 | # self.client.listZones().addCallback(_callback) 59 | # reactor.run() 60 | pass 61 | 62 | def test_listPods(self): 63 | pass 64 | 65 | def test_listClusters(self): 66 | pass 67 | 68 | def test_listHosts(self): 69 | pass 70 | 71 | def test_listCapacity(self): 72 | pass 73 | 74 | def test_listAlerts(self): 75 | pass 76 | 77 | def test_listEvents(self): 78 | pass 79 | 80 | 81 | def test_suite(): 82 | from unittest import TestSuite, makeSuite 83 | suite = TestSuite() 84 | suite.addTest(makeSuite(TestTXCloudStack)) 85 | return suite 86 | -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/tests/test_impact.py: -------------------------------------------------------------------------------- 1 | ############################################################################## 2 | # 3 | # Copyright (C) Zenoss, Inc. 2013, all rights reserved. 4 | # 5 | # This content is made available according to terms specified in 6 | # License.zenoss under the directory where your Zenoss product is installed. 7 | # 8 | ############################################################################## 9 | 10 | ''' 11 | Unit test for all-things-Impact. 12 | ''' 13 | 14 | import transaction 15 | 16 | from zope.component import subscribers 17 | 18 | from Products.Five import zcml 19 | 20 | from Products.ZenTestCase.BaseTestCase import BaseTestCase 21 | from Products.ZenUtils.guid.interfaces import IGUIDManager 22 | from Products.ZenUtils.Utils import monkeypatch 23 | 24 | from ZenPacks.zenoss.CloudStack.utils import guid, require_zenpack 25 | from ZenPacks.zenoss.CloudStack.tests.utils import ( 26 | add_contained, add_noncontained, 27 | ) 28 | 29 | 30 | @monkeypatch('Products.Zuul') 31 | def get_dmd(): 32 | ''' 33 | Retrieve the DMD object. Handle unit test connection oddities. 34 | 35 | This has to be monkeypatched on Products.Zuul instead of 36 | Products.Zuul.utils because it's already imported into Products.Zuul 37 | by the time this monkeypatch happens. 38 | ''' 39 | try: 40 | # original is injected by the monkeypatch decorator. 41 | return original() 42 | 43 | except AttributeError: 44 | connections = transaction.get()._synchronizers.data.values()[:] 45 | for cxn in connections: 46 | app = cxn.root()['Application'] 47 | if hasattr(app, 'zport'): 48 | return app.zport.dmd 49 | 50 | 51 | def impacts_for(thing): 52 | ''' 53 | Return a two element tuple. 54 | 55 | First element is a list of object ids impacted by thing. Second element is 56 | a list of object ids impacting thing. 57 | ''' 58 | from ZenPacks.zenoss.Impact.impactd.interfaces \ 59 | import IRelationshipDataProvider 60 | 61 | impacted_by = [] 62 | impacting = [] 63 | 64 | guid_manager = IGUIDManager(thing.getDmd()) 65 | for subscriber in subscribers([thing], IRelationshipDataProvider): 66 | for edge in subscriber.getEdges(): 67 | if edge.source == guid(thing): 68 | impacted_by.append(guid_manager.getObject(edge.impacted).id) 69 | elif edge.impacted == guid(thing): 70 | impacting.append(guid_manager.getObject(edge.source).id) 71 | 72 | return (impacted_by, impacting) 73 | 74 | 75 | def triggers_for(thing): 76 | ''' 77 | Return a dictionary of triggers for thing. 78 | 79 | Returned dictionary keys will be triggerId of a Trigger instance and 80 | values will be the corresponding Trigger instance. 81 | ''' 82 | from ZenPacks.zenoss.Impact.impactd.interfaces import INodeTriggers 83 | 84 | triggers = {} 85 | 86 | for sub in subscribers((thing,), INodeTriggers): 87 | for trigger in sub.get_triggers(): 88 | triggers[trigger.triggerId] = trigger 89 | 90 | return triggers 91 | 92 | 93 | def create_cloud(dmd): 94 | ''' 95 | Return a Cloud suitable for Impact functional testing. 96 | ''' 97 | # DeviceClass 98 | dc = dmd.Devices.createOrganizer('/CloudStack') 99 | dc.setZenProperty('zPythonClass', 'ZenPacks.zenoss.CloudStack.Cloud') 100 | 101 | # Endpoint 102 | cloud = dc.createInstance('cloud') 103 | 104 | # Zone 105 | from ZenPacks.zenoss.CloudStack.Zone import Zone 106 | zone1 = add_contained(cloud, 'zones', Zone('zone1')) 107 | 108 | # Pod 109 | from ZenPacks.zenoss.CloudStack.Pod import Pod 110 | pod1 = add_contained(zone1, 'pods', Pod('pod1')) 111 | 112 | # SystemVM 113 | from ZenPacks.zenoss.CloudStack.SystemVM import SystemVM 114 | systemvm1 = add_contained(pod1, 'systemvms', SystemVM('systemvm1')) 115 | 116 | # RouterVM 117 | from ZenPacks.zenoss.CloudStack.RouterVM import RouterVM 118 | routervm1 = add_contained(pod1, 'routervms', RouterVM('routervm1')) 119 | 120 | # Cluster 121 | from ZenPacks.zenoss.CloudStack.Cluster import Cluster 122 | cluster1 = add_contained(pod1, 'clusters', Cluster('cluster1')) 123 | 124 | # Host 125 | from ZenPacks.zenoss.CloudStack.Host import Host 126 | host1 = add_contained(cluster1, 'hosts', Host('host1')) 127 | add_noncontained(host1, 'systemvms', systemvm1) 128 | add_noncontained(host1, 'routervms', routervm1) 129 | 130 | # VirtualMachine 131 | from ZenPacks.zenoss.CloudStack.VirtualMachine import VirtualMachine 132 | vm1 = add_contained(zone1, 'vms', VirtualMachine('vm1')) 133 | add_noncontained(vm1, 'host', host1) 134 | 135 | return cloud 136 | 137 | 138 | class TestImpact(BaseTestCase): 139 | def afterSetUp(self): 140 | super(TestImpact, self).afterSetUp() 141 | 142 | import Products.ZenEvents 143 | zcml.load_config('meta.zcml', Products.ZenEvents) 144 | 145 | try: 146 | import ZenPacks.zenoss.DynamicView 147 | zcml.load_config('configure.zcml', ZenPacks.zenoss.DynamicView) 148 | except ImportError: 149 | return 150 | 151 | try: 152 | import ZenPacks.zenoss.Impact 153 | zcml.load_config('meta.zcml', ZenPacks.zenoss.Impact) 154 | zcml.load_config('configure.zcml', ZenPacks.zenoss.Impact) 155 | except ImportError: 156 | return 157 | 158 | import ZenPacks.zenoss.CloudStack 159 | zcml.load_config('configure.zcml', ZenPacks.zenoss.CloudStack) 160 | 161 | def cloud(self): 162 | ''' 163 | Return a CloudStack cloud device populated in a suitable way for 164 | Impact testing. 165 | ''' 166 | if not hasattr(self, '_cloud'): 167 | self._cloud = create_cloud(self.dmd) 168 | 169 | return self._cloud 170 | 171 | def assertTriggersExist(self, triggers, expected_trigger_ids): 172 | ''' 173 | Assert that each expected_trigger_id exists in triggers. 174 | ''' 175 | for trigger_id in expected_trigger_ids: 176 | self.assertTrue( 177 | trigger_id in triggers, 'missing trigger: %s' % trigger_id) 178 | 179 | @require_zenpack('ZenPacks.zenoss.Impact') 180 | @require_zenpack('ZenPacks.zenoss.XenServer') 181 | def test_XenServer(self): 182 | from ZenPacks.zenoss.XenServer.tests.test_impact import create_endpoint 183 | from ZenPacks.zenoss.XenServer.VM import VM 184 | from ZenPacks.zenoss.XenServer.VIF import VIF 185 | 186 | xen_endpoint = create_endpoint(self.dmd) 187 | xen_host = xen_endpoint.getObjByPath('hosts/host1') 188 | xen_pif = xen_endpoint.getObjByPath('hosts/host1/pifs/pif1') 189 | xen_pif.ipv4_addresses = ['10.11.12.13'] 190 | xen_pif.index_object() 191 | 192 | xen_vm = xen_endpoint.getObjByPath('vms/vm1') 193 | xen_vm_vif = xen_endpoint.getObjByPath('vms/vm1/vifs/vif1') 194 | xen_vm_vif.macaddress = '00:0c:29:fe:ab:bc' 195 | xen_vm_vif.index_object() 196 | 197 | xen_routervm = add_contained(xen_endpoint, 'vms', VM('xen_routervm1')) 198 | xen_routervm_vif = add_contained(xen_routervm, 'vifs', VIF('xen_routervm1_vif1')) 199 | xen_routervm_vif.macaddress = '00:0c:29:fe:ab:bd' 200 | xen_routervm_vif.index_object() 201 | 202 | xen_systemvm = add_contained(xen_endpoint, 'vms', VM('xen_systemvm1')) 203 | xen_systemvm_vif = add_contained(xen_systemvm, 'vifs', VIF('xen_systemvm1_vif1')) 204 | xen_systemvm_vif.macaddress = '00:0c:29:fe:ab:be' 205 | xen_systemvm_vif.index_object() 206 | 207 | host = self.cloud().getObjByPath('zones/zone1/pods/pod1/clusters/cluster1/hosts/host1') 208 | host.ip_address = xen_pif.ipv4_addresses[0] 209 | host.index_object() 210 | 211 | vm = self.cloud().getObjByPath('zones/zone1/vms/vm1') 212 | vm.mac_address = xen_vm_vif.macaddress 213 | vm.index_object() 214 | 215 | routervm = self.cloud().getObjByPath('zones/zone1/pods/pod1/routervms/routervm1') 216 | routervm.linklocal_macaddress = xen_routervm_vif.macaddress 217 | routervm.index_object() 218 | 219 | systemvm = self.cloud().getObjByPath('zones/zone1/pods/pod1/systemvms/systemvm1') 220 | systemvm.linklocal_macaddress = xen_systemvm_vif.macaddress 221 | systemvm.index_object() 222 | 223 | host_impacts, host_impacted_by = impacts_for(host) 224 | vm_impacts, vm_impacted_by = impacts_for(vm) 225 | routervm_impacts, routervm_impacted_by = impacts_for(routervm) 226 | systemvm_impacts, systemvm_impacted_by = impacts_for(systemvm) 227 | 228 | # Host -> CloudStack Host 229 | self.assertTrue( 230 | xen_host.id in host_impacted_by, 231 | 'missing impact: {0} -> {1}'.format(xen_host, host)) 232 | 233 | # VM -> CloudStack RouterVM 234 | self.assertTrue( 235 | xen_vm.id in vm_impacted_by, 236 | 'missing impact: {0} -> {1}'.format(xen_vm, vm)) 237 | 238 | # VM -> CloudStack SystemVM 239 | self.assertTrue( 240 | xen_routervm.id in routervm_impacted_by, 241 | 'missing impact: {0} -> {1}'.format(xen_routervm, routervm)) 242 | 243 | # VM -> CloudStack VirtualMachine 244 | self.assertTrue( 245 | xen_systemvm.id in systemvm_impacted_by, 246 | 'missing impact: {0} -> {1}'.format(xen_systemvm, systemvm)) 247 | -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/tests/utils.py: -------------------------------------------------------------------------------- 1 | ############################################################################## 2 | # 3 | # Copyright (C) Zenoss, Inc. 2011, 2013, all rights reserved. 4 | # 5 | # This content is made available according to terms specified in 6 | # License.zenoss under the directory where your Zenoss product is installed. 7 | # 8 | ############################################################################## 9 | 10 | import os.path 11 | import pickle 12 | import re 13 | 14 | from twisted.internet import defer 15 | 16 | 17 | def loadString(filename): 18 | f = open(os.path.join(os.path.dirname(__file__), 'data', filename), 'r') 19 | data = f.read() 20 | f.close() 21 | return data 22 | 23 | 24 | def loadPickle(filename): 25 | f = open(os.path.join(os.path.dirname(__file__), 'data', filename), 'r') 26 | data = pickle.load(f) 27 | f.close() 28 | return data 29 | 30 | 31 | def mockGetPage(url): 32 | match = re.search(r'command=(\w+)', url) 33 | if not match: 34 | return defer.fail('No JSON for URL') 35 | 36 | filename = '%sresponse.json' % match.group(1).lower() 37 | return defer.succeed(loadString(filename)) 38 | 39 | 40 | def add_contained(obj, relname, target): 41 | ''' 42 | Add and return obj to containing relname on target. 43 | ''' 44 | rel = getattr(obj, relname) 45 | rel._setObject(target.id, target) 46 | return rel._getOb(target.id) 47 | 48 | 49 | def add_noncontained(obj, relname, target): 50 | ''' 51 | Add obj to non-containing relname on target. 52 | ''' 53 | rel = getattr(obj, relname) 54 | rel.addRelation(target) 55 | -------------------------------------------------------------------------------- /ZenPacks/zenoss/CloudStack/utils.py: -------------------------------------------------------------------------------- 1 | ########################################################################### 2 | # 3 | # This program is part of Zenoss Core, an open source monitoring platform. 4 | # Copyright (C) 2011, Zenoss Inc. 5 | # 6 | # This program is free software; you can redistribute it and/or modify it 7 | # under the terms of the GNU General Public License version 2 or (at your 8 | # option) any later version as published by the Free Software Foundation. 9 | # 10 | # For complete information please visit: http://www.zenoss.com/oss/ 11 | # 12 | ########################################################################### 13 | 14 | import functools 15 | import importlib 16 | 17 | from Products.ZenUtils.guid.interfaces import IGlobalIdentifier 18 | 19 | 20 | def guid(obj): 21 | ''' 22 | Return GUID for obj. 23 | ''' 24 | return IGlobalIdentifier(obj).getGUID() 25 | 26 | 27 | def require_zenpack(zenpack_name, default=None): 28 | ''' 29 | Decorator with mandatory zenpack_name argument. 30 | 31 | If zenpack_name can't be imported, the decorated function or method 32 | will return default. Otherwise it will execute and return as 33 | written. 34 | 35 | Usage looks like the following: 36 | 37 | @require_zenpack('ZenPacks.zenoss.Impact') 38 | @require_zenpack('ZenPacks.zenoss.vCloud') 39 | def dothatthingyoudo(args): 40 | return "OK" 41 | 42 | @require_zenpack('ZenPacks.zenoss.Impact', []) 43 | def returnalistofthings(args): 44 | return [1, 2, 3] 45 | ''' 46 | def wrap(f): 47 | @functools.wraps(f) 48 | def wrapper(*args, **kwargs): 49 | try: 50 | importlib.import_module(zenpack_name) 51 | except ImportError: 52 | return 53 | 54 | return f(*args, **kwargs) 55 | 56 | return wrapper 57 | 58 | return wrap 59 | -------------------------------------------------------------------------------- /ZenPacks/zenoss/__init__.py: -------------------------------------------------------------------------------- 1 | __import__('pkg_resources').declare_namespace(__name__) 2 | -------------------------------------------------------------------------------- /impact.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenoss/ZenPacks.zenoss.CloudStack/a3156e7f13f3cd04a4cbc588c3d36d036b696a34/impact.png -------------------------------------------------------------------------------- /impact.yuml: -------------------------------------------------------------------------------- 1 | // CloudStack Impacts 2 | [CloudStackCloud{bg:darkslateblue}]1-*>[CloudStackZone{bg:darkslateblue}] 3 | [CloudStackZone{bg:darkslateblue}]1-*>[CloudStackPod{bg:darkslateblue}] 4 | [CloudStackPod{bg:darkslateblue}]1-*>[CloudStackCluster{bg:darkslateblue}] 5 | [CloudStackCluster{bg:darkslateblue}]1-*>[CloudStackHost{bg:darkslateblue}] 6 | [CloudStackSystemVM{bg:darkslateblue}]*-1>[CloudStackPod{bg:darkslateblue}] 7 | [CloudStackHost{bg:darkslateblue}]1-*>[CloudStackSystemVM{bg:darkslateblue}] 8 | [CloudStackHost{bg:darkslateblue}]1-*>[CloudStackRouterVM{bg:darkslateblue}] 9 | [CloudStackHost{bg:darkslateblue}]1-*>[CloudStackVirtualMachine{bg:darkslateblue}] 10 | [CloudStackVirtualMachine{bg:darkslateblue}]1-1>[Guest Device{bg:darkslateblue}] 11 | -------------------------------------------------------------------------------- /screenshots/cloudstack_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenoss/ZenPacks.zenoss.CloudStack/a3156e7f13f3cd04a4cbc588c3d36d036b696a34/screenshots/cloudstack_add.png -------------------------------------------------------------------------------- /screenshots/cloudstack_clusters.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenoss/ZenPacks.zenoss.CloudStack/a3156e7f13f3cd04a4cbc588c3d36d036b696a34/screenshots/cloudstack_clusters.png -------------------------------------------------------------------------------- /screenshots/cloudstack_events.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenoss/ZenPacks.zenoss.CloudStack/a3156e7f13f3cd04a4cbc588c3d36d036b696a34/screenshots/cloudstack_events.png -------------------------------------------------------------------------------- /screenshots/cloudstack_graphs1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenoss/ZenPacks.zenoss.CloudStack/a3156e7f13f3cd04a4cbc588c3d36d036b696a34/screenshots/cloudstack_graphs1.png -------------------------------------------------------------------------------- /screenshots/cloudstack_graphs2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenoss/ZenPacks.zenoss.CloudStack/a3156e7f13f3cd04a4cbc588c3d36d036b696a34/screenshots/cloudstack_graphs2.png -------------------------------------------------------------------------------- /screenshots/cloudstack_graphs3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenoss/ZenPacks.zenoss.CloudStack/a3156e7f13f3cd04a4cbc588c3d36d036b696a34/screenshots/cloudstack_graphs3.png -------------------------------------------------------------------------------- /screenshots/cloudstack_hosts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenoss/ZenPacks.zenoss.CloudStack/a3156e7f13f3cd04a4cbc588c3d36d036b696a34/screenshots/cloudstack_hosts.png -------------------------------------------------------------------------------- /screenshots/cloudstack_pods.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenoss/ZenPacks.zenoss.CloudStack/a3156e7f13f3cd04a4cbc588c3d36d036b696a34/screenshots/cloudstack_pods.png -------------------------------------------------------------------------------- /screenshots/cloudstack_zones.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zenoss/ZenPacks.zenoss.CloudStack/a3156e7f13f3cd04a4cbc588c3d36d036b696a34/screenshots/cloudstack_zones.png -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | ################################ 2 | # These variables are overwritten by Zenoss when the ZenPack is exported 3 | # or saved. Do not modify them directly here. 4 | # NB: PACKAGES is deprecated 5 | NAME = "ZenPacks.zenoss.CloudStack" 6 | VERSION = "1.3.0dev" 7 | AUTHOR = "Zenoss" 8 | LICENSE = "GPLv2" 9 | NAMESPACE_PACKAGES = ['ZenPacks', 'ZenPacks.zenoss'] 10 | PACKAGES = ['ZenPacks', 'ZenPacks.zenoss', 'ZenPacks.zenoss.CloudStack'] 11 | INSTALL_REQUIRES = [] 12 | COMPAT_ZENOSS_VERS = ">=3.2" 13 | PREV_ZENPACK_NAME = "" 14 | # STOP_REPLACEMENTS 15 | ################################ 16 | # Zenoss will not overwrite any changes you make below here. 17 | 18 | from setuptools import setup, find_packages 19 | 20 | setup( 21 | # This ZenPack metadata should usually be edited with the Zenoss 22 | # ZenPack edit page. Whenever the edit page is submitted it will 23 | # overwrite the values below (the ones it knows about) with new values. 24 | name=NAME, 25 | version=VERSION, 26 | author=AUTHOR, 27 | license=LICENSE, 28 | 29 | # This is the version spec which indicates what versions of Zenoss 30 | # this ZenPack is compatible with 31 | compatZenossVers=COMPAT_ZENOSS_VERS, 32 | 33 | # previousZenPackName is a facility for telling Zenoss that the name 34 | # of this ZenPack has changed. If no ZenPack with the current name is 35 | # installed then a zenpack of this name if installed will be upgraded. 36 | prevZenPackName=PREV_ZENPACK_NAME, 37 | 38 | # Indicate to setuptools which namespace packages the zenpack 39 | # participates in 40 | namespace_packages=NAMESPACE_PACKAGES, 41 | 42 | # Tell setuptools what packages this zenpack provides. 43 | packages=find_packages(), 44 | 45 | # Tell setuptools to figure out for itself which files to include 46 | # in the binary egg when it is built. 47 | include_package_data=True, 48 | 49 | # The MANIFEST.in file is the recommended way of including additional files 50 | # in your ZenPack. package_data is another. 51 | #package_data = {} 52 | 53 | # Indicate dependencies on other python modules or ZenPacks. This line 54 | # is modified by zenoss when the ZenPack edit page is submitted. Zenoss 55 | # tries to put add/delete the names it manages at the beginning of this 56 | # list, so any manual additions should be added to the end. Things will 57 | # go poorly if this line is broken into multiple lines or modified to 58 | # dramatically. 59 | install_requires=INSTALL_REQUIRES, 60 | 61 | # Every ZenPack egg must define exactly one zenoss.zenpacks entry point 62 | # of this form. 63 | entry_points={ 64 | 'zenoss.zenpacks': '%s = %s' % (NAME, NAME), 65 | }, 66 | 67 | # All ZenPack eggs must be installed in unzipped form. 68 | zip_safe=False, 69 | ) 70 | --------------------------------------------------------------------------------