├── LICENSE ├── README.md ├── api_server ├── api_server │ ├── __init__.py │ ├── __init__.pyc │ ├── __pycache__ │ │ ├── __init__.cpython-35.pyc │ │ ├── settings.cpython-35.pyc │ │ ├── urls.cpython-35.pyc │ │ └── wsgi.cpython-35.pyc │ ├── settings.py │ ├── settings.pyc │ ├── urls.py │ ├── urls.pyc │ ├── wsgi.py │ └── wsgi.pyc ├── apis │ ├── __init__.py │ ├── __init__.pyc │ ├── __pycache__ │ │ ├── __init__.cpython-35.pyc │ │ ├── admin.cpython-35.pyc │ │ ├── models.cpython-35.pyc │ │ ├── serializers.cpython-35.pyc │ │ ├── urls.cpython-35.pyc │ │ └── views.cpython-35.pyc │ ├── admin.py │ ├── admin.pyc │ ├── apps.py │ ├── migrations │ │ ├── 0001_initial.py │ │ ├── 0001_initial.pyc │ │ ├── __init__.py │ │ └── __init__.pyc │ ├── models.py │ ├── models.pyc │ ├── serializers.py │ ├── serializers.pyc │ ├── tests.py │ ├── urls.py │ ├── urls.pyc │ ├── views.py │ └── views.pyc ├── db.sqlite3 ├── manage.py ├── readme.md └── requirements.txt ├── assets_report ├── files │ └── assets_report │ │ ├── Compaq │ │ ├── Hpacucli │ │ │ └── Bin │ │ │ │ ├── hpacucli.exe │ │ │ │ ├── hpacuscripting.exe │ │ │ │ └── infomgr.dll │ │ └── README.txt │ │ ├── MegaCli-8.07.10-1.noarch.rpm │ │ ├── MegaCli.exe │ │ ├── MegaCli64.exe │ │ ├── dmidecode.exe │ │ ├── hpacucli-9.40-12.0.x86_64.rpm │ │ └── hpssacli-2.0-23.0.x86_64.rpm ├── lib │ ├── facter │ │ ├── bond.rb │ │ ├── cpu_core_count.rb │ │ ├── disk.rb │ │ ├── nic_info.rb │ │ ├── raid_adaptor.rb │ │ ├── raid_adaptor_count.rb │ │ ├── raid_type.rb │ │ ├── ram.rb │ │ ├── setup_time.rb │ │ ├── sn.rb │ │ └── utils.rb │ └── puppet │ │ └── reports │ │ ├── assets_report.rb │ │ ├── auth.rb │ │ └── report_setting.yaml └── manifests │ └── init.pp └── docs └── server_puppet.png /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Assets Report Plugin 2 | 3 | 简介:本项目是一个Puppet Module,内建了一个Report Processor和一些自定义Facter插件,用来自动采集服务器的资产数据。 4 | 5 | ## 一、原理 6 | 7 | 本插件基于Puppet Facter的Report机制。 8 | 9 | 概念介绍 10 | 11 | - [Puppet](https://docs.puppet.com/puppet/4.8/)是一套配置管理工具,是一个Client/Server模式的架构,可以用它来管理软件、配置文件和Service。 12 | 13 | 14 | - Puppet生态圈里有个叫[Facter](https://docs.puppet.com/facter/)的工具,运行在Agent端,可以和Puppet紧密配合完成数据采集的工作。 15 | 16 | ![puppet report](docs/server_puppet.png) 17 | 18 | 如上是Puppet Agent和Master的交互逻辑图。 19 | 20 | facter插件运行在Agent端,Agent在发送Request请求Catalog的阶段,会将自身的facts都上报给Master。而Master接到数据后可以利用自身的Report Processor对其进行二次处理,例如转发到别处。 21 | 22 | 基于该原理,我们开发了自己的Report Processor:`assets_report`,通过HTTP协议将facts post给CMDB,CMDB只需要编写相应的HTTP接口将数据入库。 23 | 24 | 本包含了如下两个组件来实现整个逻辑 25 | 26 | 1. assets_report模块:一个纯Puppet Module,内建了一个Report Processor和一些自定义Facter插件,部署在Master端。 27 | 1. Report Processor运行在Master端。 28 | 2. Facter插件会通过Master下发到Agent端并被运行以采集本机资产数据。 29 | 2. api_server:负责接收资产数据并将其入库 30 | 31 | 更多内容可参考 [数据银行之自动化资产数据采集](http://autohomeops.corpautohome.com/articles/%E6%95%B0%E6%8D%AE%E9%93%B6%E8%A1%8C%E4%B9%8B%E8%87%AA%E5%8A%A8%E5%8C%96%E8%B5%84%E4%BA%A7%E6%95%B0%E6%8D%AE%E9%87%87%E9%9B%86/) 32 | 33 | ## 二、采集插件特性 34 | 35 | 相对于Facter内建的facts,本插件提供了更多的硬件数据,例如 36 | 37 | 1. CPU个数,型号 38 | 2. 内存容量,序列号,厂商,插槽位置 39 | 3. 网卡上绑定的ip,掩码,mac,型号,且支持一个网卡上绑定多ip的场景 40 | 4. RAID卡个数,型号,内存容量,RAID Level 41 | 5. 磁盘个数,容量,序列号,厂商,所属RAID卡,插槽位置 42 | 6. 操作系统类型,版本 43 | 7. 服务器厂商,SN 44 | 45 | 高级特性:为了避免大段相同数据重复上报,减轻CMDB的数据库压力,本插件具备Cache功能。即如果一台服务器的资产数据没有发生变更,那么只会汇报`not_modify`标记。 46 | 47 | 本插件支持的操作系统有(系统必须是64位的,因为本插件中的采集工具是64位的) 48 | 49 | 1. CentOS-6 50 | 2. CentOS-7 51 | 3. Windows 2008 R2 52 | 53 | 本插件支持的服务器有 54 | 55 | 1. HP 56 | 2. DELL 57 | 3. CISCO 58 | 59 | 60 | 61 | ## 三、采集插件安装方法 62 | 63 | > 安装操作在Puppet Master端进行。 64 | 65 | 因为本插件使用了Facter机制,所以依赖 66 | 67 | 1. Ruby 68 | 2. Puppet 69 | 3. Facter 70 | 71 | 其他工具均自包含在插件里,没有外部依赖。 72 | 73 | 假定你的Puppet模块目录为`/etc/puppet/modules` 74 | 75 | ``` 76 | cd ~ 77 | git clone git@github.com:AutohomeOps/Assets_Report.git 78 | cp -r Assets_Report/assets_report /etc/puppet/modules/ 79 | ``` 80 | 81 | 在你自己的`puppet.conf`(假设默认路径是`/etc/puppet/puppet.conf`)中添加 82 | 83 | ``` 84 | reports = assets_report 85 | ``` 86 | 87 | 然后在site.pp中添加如下配置,让所有Node都安装assets_report模块 88 | 89 | ``` 90 | node default { 91 | # include assets_report 92 | class {'assets_report': } 93 | } 94 | ``` 95 | 96 | 配置完毕后,采集工具会被自动下发到Agent上进行安装。下一次Puppet Agent运行时本插件即可正常工作。 97 | 98 | 99 | 100 | ## 四、汇报组件配置方法 101 | 102 | > 配置操作在Puppet Master端进行。 103 | 104 | 配置文件为 **assets_report/lib/puppet/reports/report_setting.yaml** 105 | 106 | | 参数 | 含义 | 示例 | 107 | | ------------- | ----------- | ---------------------------------------- | 108 | | report_url | 汇报接口地址 | http://localhost/api/v1.0/asset/report/,可修改成你自己的url | 109 | | auth_required | 接口是否包含验证 | true/false,默认为false,验证代码需要在auth.rb中自己实现 | 110 | | user | 验证用户名 | 如果auth_required为true,需要填写 | 111 | | passwd | 验证密码 | 如果auth_required为true,需要填写 | 112 | | enable_cache | 是否启用cache功能 | true/false, 默认为false | 113 | 114 | 115 | 116 | ## 五、汇报接口配置方法 117 | 118 | > 配置操作在Puppet Master端进行。 119 | 120 | 本接口服务`api_server`基于一个Python编写的Web框架[Django](https://www.djangoproject.com/)开发,该组件包含了数据库设计和http api的实现。因为各家公司的数据库设计均不一致,该项目仅实现了最简单的数据建模,所以该组件的存在仅作为Demo,不可用于生产环境,读者需注意。 121 | 122 | 首先,我们需要安装一些依赖。这里假定你的OS为CentOS/RedHat 123 | 124 | ``` 125 | $ cd ~/Assets_Report/api_server 126 | 安装pip,用它来安装python模块 127 | $ sudo yum install python-pip 128 | 安装python模块依赖 129 | $ pip install -r requirements.txt 130 | ``` 131 | 132 | 初始化数据库,可以参考 [Django用户手册](https://docs.djangoproject.com/en/1.10/intro/tutorial02/) 133 | 134 | ``` 135 | $ python manage.py makemigrations apis 136 | $ python manage.py migrate 137 | 数据库为当前目录下的db.sqlite3 138 | ``` 139 | 140 | 启动http api service 141 | 142 | ``` 143 | $ sudo python manage.py runserver 80 144 | 服务将监听localhost的80端口。 145 | 146 | Django version 1.10.5, using settings 'api_server.settings' 147 | Starting development server at http://127.0.0.1:80/ 148 | Quit the server with CONTROL-C. 149 | ``` 150 | 151 | ## 152 | 153 | ## 六、使用 154 | 155 | 在Puppet Agent端手动触发 156 | 157 | ``` 158 | puppet agent -t 159 | ``` 160 | 161 | 或者 puppet agent的daemon自动运行后,数据采集上报的流程就会触发,上面的api server的80端口就会收到一次post请求,数据库里将会看到本次采集的数据。 162 | 163 | ``` 164 | ➜ api_server git:(master) ✗ sqlite3 db.sqlite3 165 | SQLite version 3.14.0 2016-07-26 15:17:14 166 | Enter ".help" for usage hints. 167 | sqlite> .tables 168 | apis_asset auth_user_user_permissions 169 | auth_group django_admin_log 170 | auth_group_permissions django_content_type 171 | auth_permission django_migrations 172 | auth_user django_session 173 | auth_user_groups 174 | sqlite> select * from apis_asset; 175 | ``` 176 | 177 | 178 | 179 | ## 七、数据格式详解 180 | 181 | { 182 | 'os_type' # 操作系统类型 183 | 'os_distribution' # 操作系统发行版本 184 | 'os_release' # 操作系统版本号 185 | 'not_modify' # 本次数据跟上次比是否有变更 186 | 'setuptime' # 系统安装时间 187 | 'sn' # 序列号 188 | 'manufactory' # 服务器制造商 189 | 'productname' # 服务器产品名称 190 | 'model' # 服务器型号 191 | 'cpu_count' # 物理CPU个数 192 | 'cpu_core_count' # CPU逻辑核数 193 | 'cpu_model' # CPU型号 194 | 'nic_count' # 网卡个数 195 | 'nic' # 网卡的详细参数 196 | 'raid_adaptor_count' # raid卡控制器个数 197 | 'raid_adaptor' # raid卡控制器详细参数 198 | 'raid_type' # raid类型 199 | 'physical_disk_driver' # 物理磁盘详细参数 200 | 'ram_size' # 内存总容量 201 | 'ram_slot' # 内存详细参数 202 | 'certname' # Puppet的certname 203 | } 204 | 205 | 206 | ## 八、开发和贡献 207 | 208 | 我们非常欢迎大家参与到开发中来,欢迎提交issue,尤其是Pull Request。 209 | 210 | ## 九、支持和社区 211 | 212 | ### QQ群 213 | 214 | 您可以加入我们的官方开源QQ群452994151进行交流。 215 | 216 | ### Mail 217 | 218 | 您可以通过autohomeops@autohome.com.cn与我们联系。 219 | 220 | ### Bug提交 221 | 222 | 如果您发现任何错误或者有任何建议,请在这里提交 223 | 224 | 225 | ### Wiki 226 | 227 | 228 | ### 博客 229 | 230 | 团队官方博客 231 | 232 | ### License 233 | 234 | 本软件遵守Apache许可证授权。有关完整的许可证文本,请参阅顶根目录中的LICENSE文件。 235 | -------------------------------------------------------------------------------- /api_server/api_server/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AutohomeCorp/Assets_Report/c2484031f0c3e14beb7bf65ff53afba523028d58/api_server/api_server/__init__.py -------------------------------------------------------------------------------- /api_server/api_server/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AutohomeCorp/Assets_Report/c2484031f0c3e14beb7bf65ff53afba523028d58/api_server/api_server/__init__.pyc -------------------------------------------------------------------------------- /api_server/api_server/__pycache__/__init__.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AutohomeCorp/Assets_Report/c2484031f0c3e14beb7bf65ff53afba523028d58/api_server/api_server/__pycache__/__init__.cpython-35.pyc -------------------------------------------------------------------------------- /api_server/api_server/__pycache__/settings.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AutohomeCorp/Assets_Report/c2484031f0c3e14beb7bf65ff53afba523028d58/api_server/api_server/__pycache__/settings.cpython-35.pyc -------------------------------------------------------------------------------- /api_server/api_server/__pycache__/urls.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AutohomeCorp/Assets_Report/c2484031f0c3e14beb7bf65ff53afba523028d58/api_server/api_server/__pycache__/urls.cpython-35.pyc -------------------------------------------------------------------------------- /api_server/api_server/__pycache__/wsgi.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AutohomeCorp/Assets_Report/c2484031f0c3e14beb7bf65ff53afba523028d58/api_server/api_server/__pycache__/wsgi.cpython-35.pyc -------------------------------------------------------------------------------- /api_server/api_server/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for api_server project. 3 | 4 | Generated by 'django-admin startproject' using Django 1.10.5. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.10/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/1.10/ref/settings/ 11 | """ 12 | 13 | import os 14 | 15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 17 | 18 | 19 | # Quick-start development settings - unsuitable for production 20 | # See https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/ 21 | 22 | # SECURITY WARNING: keep the secret key used in production secret! 23 | SECRET_KEY = '6f*@5ss5yy7qb6qur&i3r#&^#v%3e_ptk^v*jm^sk@$u_u_epk' 24 | 25 | # SECURITY WARNING: don't run with debug turned on in production! 26 | DEBUG = True 27 | 28 | ALLOWED_HOSTS = ['*'] 29 | 30 | 31 | # Application definition 32 | 33 | INSTALLED_APPS = [ 34 | 'django.contrib.admin', 35 | 'django.contrib.auth', 36 | 'django.contrib.contenttypes', 37 | 'django.contrib.sessions', 38 | 'django.contrib.messages', 39 | 'django.contrib.staticfiles', 40 | 'rest_framework', 41 | 'apis', 42 | ] 43 | 44 | MIDDLEWARE = [ 45 | 'django.middleware.security.SecurityMiddleware', 46 | 'django.contrib.sessions.middleware.SessionMiddleware', 47 | 'django.middleware.common.CommonMiddleware', 48 | 'django.middleware.csrf.CsrfViewMiddleware', 49 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 50 | 'django.contrib.messages.middleware.MessageMiddleware', 51 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 52 | ] 53 | 54 | ROOT_URLCONF = 'api_server.urls' 55 | 56 | TEMPLATES = [ 57 | { 58 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 59 | 'DIRS': [os.path.join(BASE_DIR, 'templates')] 60 | , 61 | 'APP_DIRS': True, 62 | 'OPTIONS': { 63 | 'context_processors': [ 64 | 'django.template.context_processors.debug', 65 | 'django.template.context_processors.request', 66 | 'django.contrib.auth.context_processors.auth', 67 | 'django.contrib.messages.context_processors.messages', 68 | ], 69 | }, 70 | }, 71 | ] 72 | 73 | WSGI_APPLICATION = 'api_server.wsgi.application' 74 | 75 | 76 | # Database 77 | # https://docs.djangoproject.com/en/1.10/ref/settings/#databases 78 | 79 | DATABASES = { 80 | 'default': { 81 | 'ENGINE': 'django.db.backends.sqlite3', 82 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 83 | } 84 | } 85 | 86 | 87 | # Password validation 88 | # https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators 89 | 90 | AUTH_PASSWORD_VALIDATORS = [ 91 | { 92 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 93 | }, 94 | { 95 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 96 | }, 97 | { 98 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 99 | }, 100 | { 101 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 102 | }, 103 | ] 104 | 105 | 106 | # Internationalization 107 | # https://docs.djangoproject.com/en/1.10/topics/i18n/ 108 | 109 | LANGUAGE_CODE = 'en-us' 110 | 111 | TIME_ZONE = 'UTC' 112 | 113 | USE_I18N = True 114 | 115 | USE_L10N = True 116 | 117 | USE_TZ = True 118 | 119 | 120 | # Static files (CSS, JavaScript, Images) 121 | # https://docs.djangoproject.com/en/1.10/howto/static-files/ 122 | 123 | STATIC_URL = '/static/' 124 | -------------------------------------------------------------------------------- /api_server/api_server/settings.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AutohomeCorp/Assets_Report/c2484031f0c3e14beb7bf65ff53afba523028d58/api_server/api_server/settings.pyc -------------------------------------------------------------------------------- /api_server/api_server/urls.py: -------------------------------------------------------------------------------- 1 | """api_server URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/1.10/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.conf.urls import url, include 14 | 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) 15 | """ 16 | from django.conf.urls import url, include 17 | from django.contrib import admin 18 | 19 | version = 'v1.0' 20 | 21 | urlpatterns = [ 22 | url(r'^admin/', admin.site.urls), 23 | url(r'api/%s/' % version, include('apis.urls')) 24 | ] 25 | -------------------------------------------------------------------------------- /api_server/api_server/urls.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AutohomeCorp/Assets_Report/c2484031f0c3e14beb7bf65ff53afba523028d58/api_server/api_server/urls.pyc -------------------------------------------------------------------------------- /api_server/api_server/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for api_server project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.10/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "api_server.settings") 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /api_server/api_server/wsgi.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AutohomeCorp/Assets_Report/c2484031f0c3e14beb7bf65ff53afba523028d58/api_server/api_server/wsgi.pyc -------------------------------------------------------------------------------- /api_server/apis/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AutohomeCorp/Assets_Report/c2484031f0c3e14beb7bf65ff53afba523028d58/api_server/apis/__init__.py -------------------------------------------------------------------------------- /api_server/apis/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AutohomeCorp/Assets_Report/c2484031f0c3e14beb7bf65ff53afba523028d58/api_server/apis/__init__.pyc -------------------------------------------------------------------------------- /api_server/apis/__pycache__/__init__.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AutohomeCorp/Assets_Report/c2484031f0c3e14beb7bf65ff53afba523028d58/api_server/apis/__pycache__/__init__.cpython-35.pyc -------------------------------------------------------------------------------- /api_server/apis/__pycache__/admin.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AutohomeCorp/Assets_Report/c2484031f0c3e14beb7bf65ff53afba523028d58/api_server/apis/__pycache__/admin.cpython-35.pyc -------------------------------------------------------------------------------- /api_server/apis/__pycache__/models.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AutohomeCorp/Assets_Report/c2484031f0c3e14beb7bf65ff53afba523028d58/api_server/apis/__pycache__/models.cpython-35.pyc -------------------------------------------------------------------------------- /api_server/apis/__pycache__/serializers.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AutohomeCorp/Assets_Report/c2484031f0c3e14beb7bf65ff53afba523028d58/api_server/apis/__pycache__/serializers.cpython-35.pyc -------------------------------------------------------------------------------- /api_server/apis/__pycache__/urls.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AutohomeCorp/Assets_Report/c2484031f0c3e14beb7bf65ff53afba523028d58/api_server/apis/__pycache__/urls.cpython-35.pyc -------------------------------------------------------------------------------- /api_server/apis/__pycache__/views.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AutohomeCorp/Assets_Report/c2484031f0c3e14beb7bf65ff53afba523028d58/api_server/apis/__pycache__/views.cpython-35.pyc -------------------------------------------------------------------------------- /api_server/apis/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from .models import Asset 3 | 4 | admin.site.register(Asset) -------------------------------------------------------------------------------- /api_server/apis/admin.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AutohomeCorp/Assets_Report/c2484031f0c3e14beb7bf65ff53afba523028d58/api_server/apis/admin.pyc -------------------------------------------------------------------------------- /api_server/apis/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class ApisConfig(AppConfig): 5 | name = 'apis' 6 | -------------------------------------------------------------------------------- /api_server/apis/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.10.5 on 2017-03-17 07:15 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | import jsonfield.fields 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | initial = True 12 | 13 | dependencies = [ 14 | ] 15 | 16 | operations = [ 17 | migrations.CreateModel( 18 | name='Asset', 19 | fields=[ 20 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 21 | ('certname', models.CharField(max_length=50, unique=True)), 22 | ('sn', models.CharField(max_length=100, unique=True, verbose_name='SN')), 23 | ('manufactory', models.CharField(max_length=50, verbose_name='\u670d\u52a1\u5668\u5382\u5546')), 24 | ('productname', models.CharField(max_length=50, verbose_name='\u670d\u52a1\u5668\u4ea7\u54c1\u540d\u79f0')), 25 | ('model', models.CharField(max_length=50, verbose_name='\u670d\u52a1\u5668\u578b\u53f7')), 26 | ('os_type', models.CharField(max_length=10, verbose_name='\u64cd\u4f5c\u7cfb\u7edf\u7c7b\u578b')), 27 | ('os_distribution', models.CharField(max_length=10, verbose_name='\u64cd\u4f5c\u7cfb\u7edf\u53d1\u884c\u7248\u672c')), 28 | ('os_release', models.CharField(max_length=10, verbose_name='\u64cd\u4f5c\u7cfb\u7edf\u7248\u672c\u53f7')), 29 | ('cpu_count', models.IntegerField(default=0, verbose_name='CPU\u7269\u7406\u4e2a\u6570')), 30 | ('cpu_core_count', models.IntegerField(default=0, verbose_name='CPU\u903b\u8f91\u6838\u6570')), 31 | ('cpu_model', models.CharField(max_length=50, verbose_name='CPU\u578b\u53f7')), 32 | ('nic_count', models.IntegerField(default=0, verbose_name='\u7f51\u5361\u4e2a\u6570')), 33 | ('nic', jsonfield.fields.JSONField(verbose_name='\u7f51\u5361\u4fe1\u606f')), 34 | ('raid_adaptor_count', models.IntegerField(verbose_name='Raid\u5361\u63a7\u5236\u5668\u4e2a\u6570')), 35 | ('raid_adaptor', jsonfield.fields.JSONField(null=True, verbose_name='Raid\u5361\u63a7\u5236\u5668\u7ea4\u7ec6\u4fe1\u606f')), 36 | ('raid_type', models.CharField(max_length=50, null=True, verbose_name='Raid\u7c7b\u578b')), 37 | ('physical_disk_driver', jsonfield.fields.JSONField(null=True, verbose_name='\u786c\u76d8\u8be6\u7ec6\u4fe1\u606f')), 38 | ('ram_size', models.IntegerField(default=0, verbose_name='\u5185\u5b58\u603b\u5bb9\u91cf')), 39 | ('ram_slot', jsonfield.fields.JSONField(null=True, verbose_name='\u5185\u5b58\u8be6\u7ec6\u4fe1\u606f')), 40 | ('setuptime', models.DateTimeField(blank=True, null=True, verbose_name='\u7cfb\u7edf\u5b89\u88c5\u65f6\u95f4')), 41 | ('create_at', models.DateTimeField(auto_now_add=True)), 42 | ('update_at', models.DateTimeField(auto_now=True)), 43 | ], 44 | ), 45 | ] 46 | -------------------------------------------------------------------------------- /api_server/apis/migrations/0001_initial.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AutohomeCorp/Assets_Report/c2484031f0c3e14beb7bf65ff53afba523028d58/api_server/apis/migrations/0001_initial.pyc -------------------------------------------------------------------------------- /api_server/apis/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AutohomeCorp/Assets_Report/c2484031f0c3e14beb7bf65ff53afba523028d58/api_server/apis/migrations/__init__.py -------------------------------------------------------------------------------- /api_server/apis/migrations/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AutohomeCorp/Assets_Report/c2484031f0c3e14beb7bf65ff53afba523028d58/api_server/apis/migrations/__init__.pyc -------------------------------------------------------------------------------- /api_server/apis/models.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | from django.db import models 3 | from jsonfield import JSONField 4 | # Create your models here. 5 | 6 | 7 | class Asset(models.Model): 8 | certname = models.CharField(max_length=50, unique=True) 9 | sn = models.CharField(u'SN', max_length=100, unique=True) 10 | manufactory = models.CharField(u'服务器厂商', max_length=50) 11 | productname = models.CharField(u'服务器产品名称', max_length=50) 12 | model = models.CharField(u'服务器型号', max_length=50) 13 | os_type = models.CharField(u'操作系统类型', max_length=10) 14 | os_distribution = models.CharField(u'操作系统发行版本', max_length=10) 15 | os_release = models.CharField(u'操作系统版本号', max_length=10) 16 | cpu_count = models.IntegerField(u'CPU物理个数', default=0) 17 | cpu_core_count = models.IntegerField(u'CPU逻辑核数', default=0) 18 | cpu_model = models.CharField(u'CPU型号', max_length=50) 19 | nic_count = models.IntegerField(u'网卡个数', default=0) 20 | nic = JSONField(u'网卡信息') 21 | raid_adaptor_count = models.IntegerField(u'Raid卡控制器个数') 22 | raid_adaptor = JSONField(u'Raid卡控制器纤细信息', null=True) 23 | raid_type = models.CharField(u'Raid类型', max_length=50, null=True) 24 | physical_disk_driver = JSONField(u'硬盘详细信息', null=True) 25 | ram_size = models.IntegerField(u'内存总容量', default=0) 26 | ram_slot = JSONField(u'内存详细信息', null=True) 27 | setuptime = models.DateTimeField(u'系统安装时间', blank=True, null=True) 28 | create_at = models.DateTimeField(blank=True, auto_now_add=True) 29 | update_at = models.DateTimeField(blank=True, auto_now=True) 30 | 31 | def __str__(self): 32 | return self.certname 33 | 34 | -------------------------------------------------------------------------------- /api_server/apis/models.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AutohomeCorp/Assets_Report/c2484031f0c3e14beb7bf65ff53afba523028d58/api_server/apis/models.pyc -------------------------------------------------------------------------------- /api_server/apis/serializers.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | from rest_framework import serializers 3 | from . import models as apis_models 4 | 5 | 6 | class AssetSerialzer(serializers.ModelSerializer): 7 | 8 | class Meta: 9 | model = apis_models.Asset 10 | fields = '__all__' 11 | -------------------------------------------------------------------------------- /api_server/apis/serializers.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AutohomeCorp/Assets_Report/c2484031f0c3e14beb7bf65ff53afba523028d58/api_server/apis/serializers.pyc -------------------------------------------------------------------------------- /api_server/apis/tests.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | import json 3 | import requests 4 | 5 | data = { 6 | "cpu_count": "2", 7 | "raid_type": "Primary-1, Secondary-0, RAID Level Qualifier-0", 8 | "nic_count": 8, 9 | "ram_size": 128, 10 | "setuptime": "1423552321", 11 | "manufactory": "Dell Inc.", 12 | "cpu_core_count": "24", 13 | "ram_slot": { 14 | "DIMM_B9": { 15 | "model": "DDR3", 16 | "capacity": 0, 17 | "sn": "", 18 | "manufactory": "" 19 | }, 20 | "DIMM_B8": { 21 | "model": "DDR3", 22 | "capacity": 0, 23 | "sn": "", 24 | "manufactory": "" 25 | }, 26 | "DIMM_B7": { 27 | "model": "DDR3", 28 | "capacity": 0, 29 | "sn": "", 30 | "manufactory": "" 31 | }, 32 | "DIMM_B6": { 33 | "model": "DDR3", 34 | "capacity": 0, 35 | "sn": "", 36 | "manufactory": "" 37 | }, 38 | "DIMM_B5": { 39 | "model": "DDR3", 40 | "capacity": 0, 41 | "sn": "", 42 | "manufactory": "" 43 | }, 44 | "DIMM_B4": { 45 | "model": "DDR3", 46 | "capacity": 16, 47 | "sn": "0001", 48 | "manufactory": "00CE00B300CE" 49 | }, 50 | "DIMM_B3": { 51 | "model": "DDR3", 52 | "capacity": 16, 53 | "sn": "0002", 54 | "manufactory": "00CE00B300CE" 55 | }, 56 | "DIMM_B2": { 57 | "model": "DDR3", 58 | "capacity": 16, 59 | "sn": "0003", 60 | "manufactory": "00CE00B300CE" 61 | }, 62 | "DIMM_B1": { 63 | "model": "DDR3", 64 | "capacity": 16, 65 | "sn": "0004", 66 | "manufactory": "00CE00B300CE" 67 | }, 68 | "DIMM_B12": { 69 | "model": "DDR3", 70 | "capacity": 0, 71 | "sn": "", 72 | "manufactory": "" 73 | }, 74 | "DIMM_B11": { 75 | "model": "DDR3", 76 | "capacity": 0, 77 | "sn": "", 78 | "manufactory": "" 79 | }, 80 | "DIMM_B10": { 81 | "model": "DDR3", 82 | "capacity": 0, 83 | "sn": "", 84 | "manufactory": "" 85 | }, 86 | "DIMM_A6": { 87 | "model": "DDR3", 88 | "capacity": 0, 89 | "sn": "", 90 | "manufactory": "" 91 | }, 92 | "DIMM_A7": { 93 | "model": "DDR3", 94 | "capacity": 0, 95 | "sn": "", 96 | "manufactory": "" 97 | }, 98 | "DIMM_A4": { 99 | "model": "DDR3", 100 | "capacity": 16, 101 | "sn": "0005", 102 | "manufactory": "00CE00B300CE" 103 | }, 104 | "DIMM_A5": { 105 | "model": "DDR3", 106 | "capacity": 0, 107 | "sn": "", 108 | "manufactory": "" 109 | }, 110 | "DIMM_A2": { 111 | "model": "DDR3", 112 | "capacity": 16, 113 | "sn": "0006", 114 | "manufactory": "00CE00B300CE" 115 | }, 116 | "DIMM_A3": { 117 | "model": "DDR3", 118 | "capacity": 16, 119 | "sn": "0007", 120 | "manufactory": "00CE00B300CE" 121 | }, 122 | "DIMM_A1": { 123 | "model": "DDR3", 124 | "capacity": 16, 125 | "sn": "0008", 126 | "manufactory": "00CE00B300CE" 127 | }, 128 | "DIMM_A8": { 129 | "model": "DDR3", 130 | "capacity": 0, 131 | "sn": "", 132 | "manufactory": "" 133 | }, 134 | "DIMM_A9": { 135 | "model": "DDR3", 136 | "capacity": 0, 137 | "sn": "", 138 | "manufactory": "" 139 | }, 140 | "DIMM_A10": { 141 | "model": "DDR3", 142 | "capacity": 0, 143 | "sn": "", 144 | "manufactory": "" 145 | }, 146 | "DIMM_A11": { 147 | "model": "DDR3", 148 | "capacity": 0, 149 | "sn": "", 150 | "manufactory": "" 151 | }, 152 | "DIMM_A12": { 153 | "model": "DDR3", 154 | "capacity": 0, 155 | "sn": "", 156 | "manufactory": "" 157 | } 158 | }, 159 | "raid_adaptor_count": 1, 160 | "raid_adaptor": { 161 | "adaptor_0": { 162 | "model": "PERC H710P Mini", 163 | "memory_size": "1024MB", 164 | "sn": "33J001" 165 | } 166 | }, 167 | "nic": { 168 | "bond0.112": { 169 | "macaddress": "a0:36:9f:1d:75:f1", 170 | "switch_port": "NULL", 171 | "hardware": 1, 172 | "netmask": "", 173 | "model": "", 174 | "ipaddress": "" 175 | }, 176 | "bond0": { 177 | "macaddress": "a0:36:9f:1d:75:f2", 178 | "switch_port": "NULL", 179 | "hardware": 1, 180 | "netmask": "", 181 | "model": "", 182 | "ipaddress": "" 183 | }, 184 | "em4": { 185 | "macaddress": "a0:36:9f:1d:75:f3", 186 | "switch_port": "NULL", 187 | "hardware": 1, 188 | "netmask": "", 189 | "model": "", 190 | "ipaddress": "" 191 | }, 192 | "bond0.112@bond0": { 193 | "macaddress": "ba0:36:9f:1d:75:f4", 194 | "switch_port": "NULL", 195 | "hardware": 1, 196 | "netmask": "255.255.224.0", 197 | "model": "", 198 | "ipaddress": "192.168.1.1" 199 | }, 200 | "em1": { 201 | "macaddress": "a0:36:9f:1d:75:f5", 202 | "switch_port": "NULL", 203 | "hardware": 1, 204 | "netmask": "", 205 | "model": "", 206 | "ipaddress": "" 207 | }, 208 | "em3": { 209 | "macaddress": "a0:36:9f:1d:75:f6", 210 | "switch_port": "NULL", 211 | "hardware": 1, 212 | "netmask": "", 213 | "model": "", 214 | "ipaddress": "" 215 | }, 216 | "em2": { 217 | "macaddress": "a0:36:9f:1d:75:f7", 218 | "switch_port": "NULL", 219 | "hardware": 1, 220 | "netmask": "", 221 | "model": "", 222 | "ipaddress": "" 223 | }, 224 | "p3p2": { 225 | "macaddress": "a0:36:9f:1d:75:f8", 226 | "switch_port": "NULL", 227 | "hardware": 1, 228 | "netmask": "", 229 | "model": "", 230 | "ipaddress": "" 231 | }, 232 | "p3p1": { 233 | "macaddress": "a0:36:9f:1d:75:f9", 234 | "switch_port": "NULL", 235 | "hardware": 1, 236 | "netmask": "", 237 | "model": "", 238 | "ipaddress": "" 239 | } 240 | }, 241 | "certname": "192.168.1.1", 242 | "cpu_model": "Intel(R) Xeon(R) CPU E5-2620 0 @ 2.00GHz", 243 | "os_type": "Linux", 244 | "model": "PowerEdge R620", 245 | "productname": "PowerEdge R620", 246 | "physical_disk_driver": [ 247 | { 248 | "slot": "0", 249 | "capacity": 838, 250 | "adaptor": "adaptor_0", 251 | "model": "SEAGATE LS06S0N05CDV", 252 | "enclosure": "32", 253 | "iface_type": "SAS" 254 | }, 255 | { 256 | "slot": "1", 257 | "capacity": 838, 258 | "adaptor": "adaptor_0", 259 | "model": "SEAGATE LS06S0N05K5Z", 260 | "enclosure": "32", 261 | "iface_type": "SAS" 262 | }, 263 | { 264 | "slot": "2", 265 | "capacity": 838, 266 | "adaptor": "adaptor_0", 267 | "model": "SEAGATE ST96S0N03W9A", 268 | "enclosure": "32", 269 | "iface_type": "SAS" 270 | }, 271 | { 272 | "slot": "3", 273 | "capacity": 838, 274 | "adaptor": "adaptor_0", 275 | "model": "SEAGATE ST900MM0006", 276 | "enclosure": "32", 277 | "iface_type": "SAS" 278 | } 279 | ], 280 | "sn": "CL68YX001", 281 | "os_release": "6.7", 282 | "not_modify": 0, 283 | "os_distribution": "CentOS" 284 | } 285 | url = 'http://localhost/api/v1.0/asset/report/' 286 | myreq = requests.post(url, data=json.dumps(data)) 287 | print(myreq.status_code) 288 | print(myreq.content) 289 | -------------------------------------------------------------------------------- /api_server/apis/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url, include 2 | from django.contrib import admin 3 | from rest_framework import routers, serializers, viewsets 4 | from . import views 5 | 6 | router = routers.DefaultRouter() 7 | router.register(r'assets', views.AssetViewSet) 8 | 9 | urlpatterns = [ 10 | url(r'^', include(router.urls)), 11 | url(r'asset/report/', views.report, name='asset_report'), 12 | 13 | ] 14 | -------------------------------------------------------------------------------- /api_server/apis/urls.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AutohomeCorp/Assets_Report/c2484031f0c3e14beb7bf65ff53afba523028d58/api_server/apis/urls.pyc -------------------------------------------------------------------------------- /api_server/apis/views.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | from rest_framework import viewsets 3 | from rest_framework.decorators import api_view 4 | from rest_framework.response import Response 5 | from rest_framework import status 6 | import json 7 | import time 8 | import datetime 9 | 10 | from .serializers import AssetSerialzer 11 | from . import models as apis_models 12 | 13 | class AssetViewSet(viewsets.ReadOnlyModelViewSet): 14 | queryset = apis_models.Asset.objects.all() 15 | serializer_class = AssetSerialzer 16 | 17 | 18 | @api_view(['POST', 'PUT']) 19 | def report(request): 20 | """ 21 | 汇报信息入库 22 | :param request: 23 | :return: 24 | """ 25 | data = request.body 26 | 27 | try: 28 | data = json.loads(data) 29 | except ValueError as e: 30 | return Response({'code': -1, 'message': 'invalid data provided. Err:%s' % e}, status=status.HTTP_400_BAD_REQUEST) 31 | 32 | not_modify = data.pop('not_modify') 33 | data['setuptime'] = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(int(data['setuptime']))) 34 | 35 | certname = data['certname'] 36 | asset = apis_models.Asset.objects.filter(certname=certname) 37 | 38 | if len(asset) == 1: 39 | if not_modify == 1: 40 | asset.update(update_at=datetime.datetime.now()) 41 | else: 42 | data['update_at'] = datetime.datetime.now() 43 | asset.update(**data) 44 | else: 45 | apis_models.Asset.objects.create(**data) 46 | 47 | return Response({'code': 0, 'message': 'success'}, status=status.HTTP_200_OK) 48 | -------------------------------------------------------------------------------- /api_server/apis/views.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AutohomeCorp/Assets_Report/c2484031f0c3e14beb7bf65ff53afba523028d58/api_server/apis/views.pyc -------------------------------------------------------------------------------- /api_server/db.sqlite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AutohomeCorp/Assets_Report/c2484031f0c3e14beb7bf65ff53afba523028d58/api_server/db.sqlite3 -------------------------------------------------------------------------------- /api_server/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "api_server.settings") 7 | try: 8 | from django.core.management import execute_from_command_line 9 | except ImportError: 10 | # The above import may fail for some other reason. Ensure that the 11 | # issue is really that Django is missing to avoid masking other 12 | # exceptions on Python 2. 13 | try: 14 | import django 15 | except ImportError: 16 | raise ImportError( 17 | "Couldn't import Django. Are you sure it's installed and " 18 | "available on your PYTHONPATH environment variable? Did you " 19 | "forget to activate a virtual environment?" 20 | ) 21 | raise 22 | execute_from_command_line(sys.argv) 23 | -------------------------------------------------------------------------------- /api_server/readme.md: -------------------------------------------------------------------------------- 1 | ## 简介 2 | 3 | 一个简单的基于django-rest-framework的http api。 4 | 5 | ## 依赖 6 | 7 | Django==1.10.5 8 | djangorestframework==3.5.3 9 | jsonfield==1.0.3 10 | requests==2.12.4 11 | 12 | ## 安装依赖 13 | 14 | pip install -r requirements.txt 15 | 16 | ## 使用 17 | 18 | 19 | 初始化数据库 20 | 21 | $ python manage.py makemigrations apis 22 | $ python manage.py migrate 23 | 数据库为当前目录下的db.sqlite3 24 | 25 | 启动http api service 26 | 27 | $ sudo python manage.py runserver 80 28 | 服务将监听localhost的80端口。 29 | 30 | Django version 1.10.5, using settings 'api_server.settings' 31 | Starting development server at http://127.0.0.1:80/ 32 | Quit the server with CONTROL-C. 33 | 34 | 35 | 36 | ## 参考资料 37 | 38 | - django 用法参考[官方文档](https://docs.djangoproject.com/en/1.10/) 39 | - djangorestframework 用法参考[官方文档](http://www.django-rest-framework.org/) 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /api_server/requirements.txt: -------------------------------------------------------------------------------- 1 | Django==1.10.5 2 | djangorestframework==3.5.3 3 | jsonfield==1.0.3 4 | requests==2.12.4 5 | -------------------------------------------------------------------------------- /assets_report/files/assets_report/Compaq/Hpacucli/Bin/hpacucli.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AutohomeCorp/Assets_Report/c2484031f0c3e14beb7bf65ff53afba523028d58/assets_report/files/assets_report/Compaq/Hpacucli/Bin/hpacucli.exe -------------------------------------------------------------------------------- /assets_report/files/assets_report/Compaq/Hpacucli/Bin/hpacuscripting.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AutohomeCorp/Assets_Report/c2484031f0c3e14beb7bf65ff53afba523028d58/assets_report/files/assets_report/Compaq/Hpacucli/Bin/hpacuscripting.exe -------------------------------------------------------------------------------- /assets_report/files/assets_report/Compaq/Hpacucli/Bin/infomgr.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AutohomeCorp/Assets_Report/c2484031f0c3e14beb7bf65ff53afba523028d58/assets_report/files/assets_report/Compaq/Hpacucli/Bin/infomgr.dll -------------------------------------------------------------------------------- /assets_report/files/assets_report/Compaq/README.txt: -------------------------------------------------------------------------------- 1 | HP Array Configuration Utility CLI 2 | Version 8.28.13.0 (windows32) 3 | 4/14/2009 4 | 5 | 6 | Description 7 | ----------- 8 | 9 | The Array Configuration Utility CLI is a commandline-based disk 10 | configuration program for Smart Array Controllers and 11 | RAID Array Controllers. 12 | 13 | 14 | Support 15 | ------- 16 | 17 | Supported Operating Systems 18 | 19 | Microsoft Windows 2000 20 | Microsoft Windows Server 2003 21 | Microsoft Windows Server 2003 64-bit ES 22 | Microsoft Windows Server 2008 23 | 24 | Supported Controllers 25 | 26 | Smart Array products: 27 | Smart Array 5312 Controller 28 | Smart Array 5302 Controller 29 | Smart Array 5304 Controller 30 | Smart Array 532 Controller 31 | Smart Array 5i Controller 32 | Smart Array 641 Controller 33 | Smart Array 642 Controller 34 | Smart Array 6400 Controller 35 | Smart Array 6400 EM Controller 36 | Smart Array 6i Controller 37 | Smart Array P600 Controller 38 | Smart Array P400 Controller 39 | Smart Array P400i Controller 40 | Smart Array E200 Controller 41 | Smart Array E200i Controller 42 | Smart Array P800 Controller 43 | Smart Array E500 Controller 44 | Smart Array P700m Contoller 45 | Smart Array P410i Controller 46 | Smart Array P411 Controller 47 | Smart Array P212 Controller 48 | Smart Array P410i ZMR Controller 49 | Smart Array P411 ZMR Controller 50 | Smart Array P212 ZMR Controller 51 | Smart Array B110i SATA RAID 52 | 53 | MSA products: 54 | MSA500 Controller 55 | MSA500 G2 Controller 56 | MSA1000 Controller 57 | MSA1500 CS Controller 58 | MSA20 Controller 59 | 60 | Installing & Running the Array Configuration Utility CLI 61 | -------------------------------------------------------------- 62 | 63 | Run the CLI: 64 | 1. Install the CLI component onto your system. 65 | 2. When component installation is complete, click Start and navigate to 66 | Programs, HP System Tools, HP Array Configuration Utility CLI. 67 | By default this will run the CLI in command prompt environment. 68 | 69 | The CLI can also be started by changing to the directory in which it 70 | was installed and doing the following: 71 | 72 | To enter the ACU CLI console type: 73 | hpacucli 74 | 75 | Commands can also be executed from outside the 76 | ACU CLI console using the syntax: 77 | hpacucli 78 | 79 | Type "hpacucli help" or type "help" at the CLI prompt for usage details. 80 | 81 | 82 | Exiting CLI: 83 | 1. To exit the ACU CLI, type "exit" while at the CLI command console. 84 | 85 | 86 | Additional Notes 87 | ---------------- 88 | * The availability of RAID 1 and RAID 1+0 fault tolerance settings is dependant 89 | upon the number of physical drives selected when creating a logical drive. When two 90 | drives are selected the RAID 1 setting is made available. When four or more physical 91 | drives have been selected, RAID 1+0 will replace RAID 1. 92 | * When creating logical drives on an existing array, the user can target the array 93 | by specifying drives= in the create operation. Example: 94 | ctrl ch=rack1 create type=ld drives=1:1,1:2,1:3 size=333 95 | Where array A has drives 1:1,1:2,1:3 and at least 333 MB available free space. 96 | * CLI now has simple return codes. A failure returns 1 and a 97 | success returns 0. 98 | * Except for show commands, the CLI locks each external controller on which it 99 | performs an operation when the command starts and unlocks it when the command is 100 | complete. This prevents the CLI from tying up a controller, but also prevents 101 | errors from occurring while another configuration utility is being run. The 102 | CLI does not attempt to lock controllers when performing a show command, nor 103 | does it lock controllers for an entire session. Note that this differs from ACU's 104 | session-style locking scheme. 105 | 106 | Known Issues 107 | ------------ 108 | 109 | * When using the CLI console, pressing the up arrow does not cycle 110 | through commands in Linux. 111 | * CLI commands are not editable when they wrap to the next line. 112 | 113 | 114 | Feedback 115 | -------- 116 | 117 | For support for ACU CLI or Smart Array controllers, please visit the web at 118 | http://support.hp.com. 119 | For feedback or suggestions on ACU CLI, please send comments to acu@hp.com; 120 | however, we regret support cannot be provided through this address. -------------------------------------------------------------------------------- /assets_report/files/assets_report/MegaCli-8.07.10-1.noarch.rpm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AutohomeCorp/Assets_Report/c2484031f0c3e14beb7bf65ff53afba523028d58/assets_report/files/assets_report/MegaCli-8.07.10-1.noarch.rpm -------------------------------------------------------------------------------- /assets_report/files/assets_report/MegaCli.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AutohomeCorp/Assets_Report/c2484031f0c3e14beb7bf65ff53afba523028d58/assets_report/files/assets_report/MegaCli.exe -------------------------------------------------------------------------------- /assets_report/files/assets_report/MegaCli64.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AutohomeCorp/Assets_Report/c2484031f0c3e14beb7bf65ff53afba523028d58/assets_report/files/assets_report/MegaCli64.exe -------------------------------------------------------------------------------- /assets_report/files/assets_report/dmidecode.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AutohomeCorp/Assets_Report/c2484031f0c3e14beb7bf65ff53afba523028d58/assets_report/files/assets_report/dmidecode.exe -------------------------------------------------------------------------------- /assets_report/files/assets_report/hpacucli-9.40-12.0.x86_64.rpm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AutohomeCorp/Assets_Report/c2484031f0c3e14beb7bf65ff53afba523028d58/assets_report/files/assets_report/hpacucli-9.40-12.0.x86_64.rpm -------------------------------------------------------------------------------- /assets_report/files/assets_report/hpssacli-2.0-23.0.x86_64.rpm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AutohomeCorp/Assets_Report/c2484031f0c3e14beb7bf65ff53afba523028d58/assets_report/files/assets_report/hpssacli-2.0-23.0.x86_64.rpm -------------------------------------------------------------------------------- /assets_report/lib/facter/bond.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift(File.dirname(__FILE__)) unless $LOAD_PATH.include?(File.dirname(__FILE__)) 2 | require "rubygems" 3 | require 'json' 4 | require 'utils' 5 | 6 | def bond_pattern_filter(content) 7 | result = [] 8 | needle = 'Slave Interface' 9 | content.split("\n").each do |line| 10 | if line.start_with?(needle) 11 | result.push(line.split(':')[1].strip) 12 | end 13 | end 14 | return result 15 | end 16 | 17 | Facter.add(:bonding) do 18 | confine :kernel => 'Linux' 19 | setcode do 20 | 21 | bond_nic = Dir.glob('/proc/net/bonding/*') 22 | response = {} 23 | 24 | bond_nic.each do |bond_proc| 25 | bond_name = File.basename(bond_proc) 26 | nic_hardware = bond_pattern_filter(File.read(bond_proc)) 27 | nic_hardware.each do |nic| 28 | response[nic] = bond_name 29 | end 30 | end 31 | 32 | JSON.dump(response) 33 | 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /assets_report/lib/facter/cpu_core_count.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift(File.dirname(__FILE__)) unless $LOAD_PATH.include?(File.dirname(__FILE__)) 2 | require "rubygems" 3 | require 'utils' 4 | 5 | Facter.add(:cpu_core_count) do 6 | confine :kernel => 'Linux' 7 | setcode do 8 | Facter.value(:processorcount) 9 | end 10 | end 11 | 12 | 13 | Facter.add(:cpu_core_count) do 14 | confine :kernel => 'windows' 15 | setcode do 16 | 17 | cpu_core_count = 0 18 | 19 | require 'facter/util/wmi' 20 | cmd = 'wmic computersystem get NumberOfLogicalProcessors /VALUE' 21 | output = Utils.facter_exec(cmd) 22 | 23 | if not output.empty? 24 | output.split("\n").each do |line| 25 | strip_line = line.strip 26 | next if strip_line.empty? 27 | if strip_line.start_with?('NumberOfLogicalProcessors') 28 | key, value = strip_line.split('=') 29 | cpu_core_count = value.to_i 30 | end 31 | end 32 | 33 | end 34 | 35 | # for windows 2003 and below 36 | if 0 == cpu_core_count 37 | cpu_core_count = ENV['NUMBER_OF_PROCESSORS'].to_i 38 | end 39 | 40 | cpu_core_count 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /assets_report/lib/facter/disk.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift(File.dirname(__FILE__)) unless $LOAD_PATH.include?(File.dirname(__FILE__)) 2 | require "rubygems" 3 | require 'pp' 4 | require 'json' 5 | #require_relative 'utils' 6 | require 'utils' 7 | 8 | def mega_patter_match(needle) 9 | grep_pattern = ['Adapter', 'Slot', 'Raw Size', 'Inquiry', 'PD Type', 'Enclosure Device ID'] 10 | grep_pattern.each do |pattern| 11 | return true if needle.start_with?(pattern) 12 | end 13 | return false 14 | end 15 | 16 | def megacli_get_disk_metric(cmd) 17 | result = [] 18 | 19 | output = Utils.facter_exec(cmd) 20 | if output.strip.empty? 21 | return result 22 | end 23 | 24 | filted_content = output.split("\n").select do |line| 25 | mega_patter_match(line) 26 | end 27 | 28 | filted_content_string = filted_content.join("\n") 29 | 30 | adaptor_section = filted_content_string.split(/Adapter.*/).select {|e| not e.strip.empty? } 31 | adaptor_section.each_with_index do |section, adaptor_idx| 32 | 33 | pair_sequence = [] 34 | section.split("\n").each do |record| 35 | next if record.strip().empty? 36 | key, value = record.split(":") 37 | pair_sequence.push([key.strip, value.strip]) 38 | end 39 | 40 | first_flag = pair_sequence[0][0] 41 | element = {} 42 | pair_sequence.each_with_index do |pair, idx| 43 | key, value = pair 44 | 45 | if key == first_flag 46 | element[key] = value 47 | 48 | # this is the last one , or , it comes the duplicated key 49 | elsif (idx+1) == pair_sequence.size or pair_sequence[idx+1][0] == first_flag 50 | element[key] = value 51 | element['adaptor'] = "adaptor_#{adaptor_idx}" 52 | result.push(element) 53 | element = {} 54 | else 55 | element[key] = value 56 | end 57 | end 58 | 59 | end 60 | # convert key name to uniform name 61 | response = [] 62 | result.each do |e| 63 | _d = {} 64 | e.each do |k, v| 65 | if k == 'Slot Number' 66 | _d['slot'] = v 67 | elsif k == 'PD Type' 68 | _d['iface_type'] = v 69 | elsif k == 'Raw Size' 70 | # v like this: "138.803 GB [0x1159bb10 Sectors]" 71 | _segment = v.split() 72 | unit = _segment[1].strip 73 | if unit == 'GB' 74 | _d['capacity'] = _segment[0].to_i 75 | elsif unit == 'TB' 76 | _d['capacity'] = _segment[0].to_f.round * 1024 77 | elsif unit == 'MB' 78 | _d['capacity'] = _segment[0].to_i / 1024 79 | end 80 | elsif k == 'Inquiry Data' 81 | _d['model'] = v 82 | elsif k == 'Enclosure Device ID' 83 | _d['enclosure'] = v 84 | else 85 | _d[k] = v 86 | end 87 | end 88 | response.push(_d) 89 | end 90 | 91 | return response 92 | end 93 | 94 | 95 | def hpcli_get_disk_metric(cmd) 96 | 97 | response = [] 98 | output = Utils.facter_exec(cmd) 99 | 100 | if not output.empty? 101 | 102 | enclosure = '' 103 | output.split("\n").each do |line| 104 | # "physicaldrive 2I:1:5 (port 2I:box 1:bay 5, SAS, 300 GB, OK)" 105 | # 1:"2I" 2:"2I" 3:"SAS" 4:"300"> 106 | enclosure_pattern = /.*Slot (\d+).*/ 107 | drive_pattern = /^physicaldrive (\w+:\d:\d) \(port.*\w+:box \d:bay \d, (.+?), (\d+) (\w{2}),.*/ 108 | enclosure_m = enclosure_pattern.match(line.strip) 109 | 110 | if enclosure_m 111 | enclosure = enclosure_m[1] 112 | end 113 | 114 | m = drive_pattern.match(line.strip) 115 | next if not m 116 | 117 | unit = m[4].strip 118 | _size = m[3] 119 | if unit == 'GB' 120 | _size = _size.to_i 121 | elsif unit == 'TB' 122 | _size = _size.to_f.round * 1024 123 | elsif unit == 'MB' 124 | _size = _size.to_i / 1024 125 | end 126 | 127 | if m[2] == 'Solid State SAS' 128 | iface_type = 'SSD' 129 | else 130 | iface_type = m[2] 131 | end 132 | 133 | response.push({ 134 | 'capacity' => _size, 135 | 'iface_type' => iface_type, 136 | 'slot' => m[1], 137 | 'model' => '', 138 | 'sn' => '', 139 | 'enclosure' => enclosure, 140 | }) 141 | end 142 | end 143 | return response 144 | end 145 | 146 | def ucsc_get_disk_metric() 147 | ret = [] 148 | ret_list = [] 149 | cmd = "storcli show ctrlcount J" 150 | output = Utils.facter_exec(cmd) 151 | ctrs_info = JSON.parse(output)['Controllers'] 152 | # get conctolers count 153 | for ctr in ctrs_info 154 | if ctr.has_key?('Response Data') && ctr['Response Data'].has_key?('Controller Count') 155 | num_ctrs = ctr['Response Data']['Controller Count'] 156 | else 157 | num_ctrs = -1 158 | end 159 | end 160 | 161 | for x in 0..num_ctrs-1 162 | output = `storcli /c#{x} show J` 163 | ctr_info = JSON.parse(output)['Controllers'] 164 | for pd in ctr_info 165 | plist = pd['Response Data']['PD LIST'] 166 | for p in plist 167 | p['EID:Slt'] = "#{x}:#{p['EID:Slt']}" 168 | end 169 | end 170 | ret = ret + plist 171 | end 172 | for r in ret 173 | if r['Size'].include?("TB") 174 | r['Size'] = r['Size'].split(" ")[0].to_f*1000 175 | else 176 | r['Size'] = r['Size'].split(" ")[0].to_f 177 | end 178 | ret_hash=Hash["capacity" => r['Size'],"model" => r['Model'].strip,"slot" => r['EID:Slt'],"iface_type"=>r['Intf']] 179 | ret_list = ret_list.push(ret_hash) 180 | end 181 | return ret_list 182 | end 183 | 184 | def disk_name_match(needle) 185 | pattern = ['sd', 'hd'] 186 | pattern.each do |pt| 187 | return true if needle.start_with?(pt) 188 | end 189 | return false 190 | end 191 | 192 | 193 | Facter.add(:physical_disk_driver) do 194 | # only hp machine will use hpacucli to get disk information, 195 | # dell and cisco machine will get disk information by megacli 196 | # regardless if have a raid card or not, 197 | 198 | confine :kernel => 'Linux' 199 | setcode do 200 | 201 | response = [] 202 | 203 | 204 | # have a raid card 205 | if Facter.value(:raid_adaptor_count).to_i > 0 # <= First 206 | if Facter.value(:manufacturer) =~ /.*HP.*/i 207 | 208 | cli = Utils.hpacucli_for_linux 209 | cmd = "#{cli} ctrl all show config" 210 | response = hpcli_get_disk_metric(cmd) if File.exist?(cli) 211 | 212 | elsif Facter.value(:productname) == "UCSC-C240-M4L" 213 | response = ucsc_get_disk_metric 214 | 215 | else 216 | 217 | cli = Utils.megacli_for_linux 218 | cmd = "#{cli} -PDList -aALL -NoLog" 219 | #cmd = "#{cli} -PDList -aALL |grep -E '(Adapter|Slot|Raw Size|Inquiry|PD Type)'" 220 | 221 | response = megacli_get_disk_metric(cmd) if File.exist?(cli) 222 | end 223 | 224 | else # <= First 225 | # have no raid card 226 | block_devices = Facter.value('blockdevices') 227 | block_devices_sequence = block_devices.split(',').select {|d| disk_name_match(d)} 228 | block_devices_sequence.each do |device_name| 229 | _d = {} 230 | _d['model'] = Facter.value("blockdevice_#{device_name}_model") 231 | _d['manufactory'] = Facter.value("blockdevice_#{device_name}_vendor") 232 | _d['capacity'] = Facter.value("blockdevice_#{device_name}_size").to_i / (1024**3) # unit: GB 233 | _d['sn'] = '' 234 | _d['slot'] = device_name 235 | _d['iface_type'] = '' 236 | _d['name'] = device_name 237 | _d['adaptor'] = '' 238 | response.push(_d) 239 | end 240 | 241 | end # <= First 242 | 243 | JSON.dump(response) 244 | end 245 | end 246 | 247 | 248 | 249 | 250 | 251 | Facter.add(:physical_disk_driver) do 252 | # Dell and cisco machine will get disk information by megacli, 253 | # other machine will use WMI, 254 | 255 | confine :kernel => 'windows' 256 | setcode do 257 | 258 | response = [] 259 | 260 | # have a raid card 261 | if Facter.value(:raid_adaptor_count).to_i > 0 # <= First 262 | if Facter.value(:manufacturer) =~ /.*HP.*/i 263 | # hp machine 264 | cli = Utils.hpacucli_for_win 265 | cmd = "#{cli} ctrl all show config" 266 | response = hpcli_get_disk_metric(cmd) if File.exist?(cli) 267 | else 268 | # Dell or UCS machine 269 | # Facter.value(:manufacturer) =~ /.*(Dell|Cisco).*/i 270 | cli = Utils.megacli_for_win 271 | cmd = "#{cli} -PDList -aALL" 272 | 273 | response = megacli_get_disk_metric(cmd) if File.exist?(cli) 274 | end 275 | else # <= First 276 | # do not have raid card 277 | Facter::Util::WMI.execquery("select * from Win32_DiskDrive").each do | item | 278 | response.push( 279 | { 280 | 'capacity' => item.size.to_i / (1024**3), # unite GB 281 | 'iface_type' => item.InterfaceType, 282 | 'slot' => item.Index, 283 | 'model' => item.Model.strip, 284 | 'sn' => item.SerialNumber.strip, 285 | } 286 | ) 287 | 288 | end 289 | end # <= First 290 | JSON.dump(response) 291 | end 292 | end 293 | 294 | 295 | -------------------------------------------------------------------------------- /assets_report/lib/facter/nic_info.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | require "rubygems" 3 | require 'json' 4 | 5 | def more_ip_plan_for_win(nic_name,nic) 6 | nic_name_count = 0 7 | new_nic_name = nic_name 8 | while nic.has_key?(new_nic_name) 9 | new_nic_name = new_nic_name.split(":")[0] + ":" + nic_name_count.to_s 10 | nic_name_count += 1 11 | end 12 | nic[new_nic_name] = {} 13 | nic[new_nic_name]['macaddress'] = nic[nic_name]['macaddress'] 14 | nic[new_nic_name]['ipaddress'] = nic[nic_name]['ipaddress'] 15 | nic[new_nic_name]['netmask'] = nic[nic_name]['netmask'] 16 | return nic 17 | end 18 | 19 | def more_ip_plan_for_linux(nic_name,nic,new_nic_name) 20 | nic[new_nic_name] = {} 21 | nic[new_nic_name]['macaddress'] = nic[nic_name]['macaddress'] 22 | nic[new_nic_name]['ipaddress'] = nic[nic_name]['ipaddress'] 23 | nic[new_nic_name]['netmask'] = nic[nic_name]['netmask'] 24 | return nic 25 | end 26 | 27 | def full_nic_for_win(nic_name,nic) 28 | nic_name_count = 0 29 | new_nic_name = nic_name + ":" + nic_name_count.to_s 30 | if nic[nic_name].has_key?('ipaddress') 31 | if nic[nic_name]['ipaddress'] == nil 32 | nic[nic_name]['ipaddress'] = '' 33 | end 34 | else 35 | nic[nic_name]['ipaddress'] = '' 36 | end 37 | 38 | while nic.has_key?(new_nic_name) 39 | nic[new_nic_name]['hardware'] = 1 40 | nic[new_nic_name]['model'] = '' 41 | if nic[new_nic_name]['ipaddress'] == nil 42 | nic[new_nic_name]['ipaddress'] = '' 43 | end 44 | nic_name_count += 1 45 | new_nic_name = new_nic_name.split(":")[0] + ":" + nic_name_count.to_s 46 | end 47 | for x in nic 48 | if not x[1].has_key?('hardware') 49 | x[1]['hardware'] = 1 50 | end 51 | if not x[1].has_key?('model') 52 | x[1]['model'] = '' 53 | end 54 | end 55 | return nic 56 | end 57 | 58 | def full_nic_for_linux(nic_name,nic) 59 | nic_name_count = 0 60 | new_nic_name = nic_name + ":" + nic_name_count.to_s 61 | if nic[nic_name].has_key?('ipaddress') 62 | if nic[nic_name]['ipaddress'] == nil 63 | nic[nic_name]['ipaddress'] = '' 64 | end 65 | else 66 | nic[nic_name]['ipaddress'] = '' 67 | end 68 | if nic[nic_name].has_key?('netmask') 69 | if nic[nic_name]['netmask'] == nil 70 | nic[nic_name]['netmask'] = '' 71 | end 72 | else 73 | nic[nic_name]['netmask'] = '' 74 | end 75 | while nic.has_key?(new_nic_name) 76 | if nic[new_nic_name]['ipaddress'] == nil 77 | nic[new_nic_name]['ipaddress'] = '' 78 | end 79 | nic_name_count += 1 80 | new_nic_name = new_nic_name.split(":")[0] + ":" + nic_name_count.to_s 81 | end 82 | for x in nic 83 | if not x[1].has_key?('hardware') 84 | x[1]['hardware'] = 1 85 | end 86 | if not x[1].has_key?('model') 87 | x[1]['model'] = '' 88 | end 89 | end 90 | return nic 91 | end 92 | 93 | def get_ip_for_win_ZH_CN() 94 | nic = {} 95 | ipconfig_replace = %x{"ipconfig"/all"}.gsub(" ","") 96 | ipconfig_arr = ipconfig_replace.split("\n") 97 | nil_arr = [""] 98 | ipconfig_arr = ipconfig_arr - nil_arr 99 | for ipline in ipconfig_arr 100 | ip_info = ipline.split(":") 101 | if ipline.include?"以太网适配器".encode('gbk') 102 | nic_name = ipline.gsub("以太网适配器".encode('gbk'),"").gsub(":","") 103 | nic[nic_name] = {} 104 | nic[nic_name]['hardware'] = 1 105 | nic[nic_name]['model'] = '' 106 | elsif ipline.include?"物理地址".encode('gbk') 107 | nic[nic_name]['macaddress'] = ip_info[1] 108 | elsif ipline.include?"IPv4".encode('gbk') 109 | if nic[nic_name].has_key?('ipaddress') 110 | nic = more_ip_plan_for_win(nic_name, nic) 111 | end 112 | nic[nic_name]['ipaddress'] = ip_info[1].split("(")[0] 113 | elsif ipline.include?"子网掩码".encode('gbk') 114 | nic[nic_name]['netmask'] = ip_info[1] 115 | nic = full_nic_for_win(nic_name,nic) 116 | end 117 | end 118 | return nic 119 | end 120 | 121 | def get_ip_for_win_EN_US() 122 | nic = {} 123 | ipconfig_replace = %x{"ipconfig"/all"} 124 | ipconfig_arr = ipconfig_replace.split("\n") 125 | nil_arr = [""] 126 | ipconfig_arr = ipconfig_arr - nil_arr 127 | for ipline in ipconfig_arr 128 | ip_info = ipline.split(":") 129 | if (ipline.include?"Ethernet" and ipline.include?"adapter") 130 | nic_name = ipline.gsub("Ethernet","").gsub("adapter","").gsub(":","").strip() 131 | nic[nic_name] = {} 132 | nic[nic_name]['hardware'] = 1 133 | nic[nic_name]['model'] = '' 134 | end 135 | if ip_info.length > 1 136 | if (ipline.include?"Physical" and ipline.include?"Address") 137 | nic[nic_name]['macaddress'] = ip_info[1].strip() 138 | elsif ipline.include?"IPv4" 139 | if nic[nic_name].has_key?('ipaddress') 140 | nic = more_ip_plan_for_win(nic_name, nic) 141 | end 142 | nic[nic_name]['ipaddress'] = ip_info[1].split("(")[0].strip() 143 | elsif (ipline.include?"Subnet" and ipline.include?"Mask") 144 | nic[nic_name]['netmask'] = ip_info[1].strip() 145 | end 146 | if not nic_name == nil 147 | nic = full_nic_for_win(nic_name,nic) 148 | end 149 | end 150 | end 151 | return nic 152 | end 153 | 154 | def get_ip_for_win() 155 | ipconfig_replace = %x{"ipconfig"/all"}.gsub(" ","") 156 | if ipconfig_replace.include?"以太网适配器".encode('gbk') 157 | nic = get_ip_for_win_ZH_CN() 158 | else 159 | nic = get_ip_for_win_EN_US() 160 | end 161 | return nic 162 | end 163 | 164 | def get_ip_for_linux() 165 | nic = {} 166 | ipconfig_replace = `ip address show` 167 | ipconfig_arr = ipconfig_replace.split("\n") 168 | ipconfig_arr = ipconfig_arr - [''] 169 | for ipline in ipconfig_arr 170 | if not ipline[0, 1] == " " 171 | nic_name = ipline.split(" ")[1].gsub(" ","") 172 | if nic_name[-1, 1] == ":" 173 | nic_name = nic_name.slice(0, nic_name.length - 1 ) 174 | end 175 | nic[nic_name] = {} 176 | nic[nic_name]['hardware'] = 1 177 | nic[nic_name]['model'] = '' 178 | elsif (ipline.include?"inet" and not(ipline.include?"inet6")) 179 | ipconfig_replace = ipline.split(" ") - [""] 180 | if not ipconfig_replace[-1] == nic_name 181 | nic = more_ip_plan_for_linux(nic_name,nic,ipconfig_replace[-1]) 182 | end 183 | match_auto = /\d+\.\d+\.\d+\.\d+/.match(ipconfig_replace[1]) 184 | nic[nic_name]['ipaddress'] = match_auto[0] 185 | nic[nic_name]['netmask'] = auto_netmask(ipconfig_replace[1].slice(ipconfig_replace[1].rindex("/") + 1, 10)) 186 | elsif not /([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}/.match(ipline) == nil 187 | nic[nic_name]['macaddress'] = /([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}/.match(ipline)[0] 188 | end 189 | nic = full_nic_for_linux(nic_name,nic) 190 | end 191 | return nic 192 | end 193 | 194 | def check_mac(nic) 195 | for x in nic 196 | if not x[1].has_key?('macaddress') 197 | nic.delete(x[0]) 198 | next 199 | end 200 | if x[1]['ipaddress'] == '127.0.0.1' 201 | #p 'del from ip' 202 | nic.delete(x[0]) 203 | next 204 | end 205 | if x[1]['macaddress'] == nil 206 | nic.delete(x[0]) 207 | next 208 | end 209 | if x[0].include?('lo:') 210 | #p 'del from name' 211 | nic.delete(x[0]) 212 | next 213 | end 214 | end 215 | return nic 216 | end 217 | 218 | def auto_netmask(num) 219 | count = num.to_i/8 220 | lift = num.to_i%8 221 | netmask = "255." * count + Integer("0b" + "1" * lift +"0" * (8 - lift)).to_s 222 | netmask_info = netmask.split(".") 223 | if netmask_info.size > 4 224 | netmask = netmask_info[0] + "." + netmask_info[1] + "." + netmask_info[1] + "." + netmask_info[1] 225 | elsif netmask_info.size < 4 226 | new_arr = netmask_info 227 | while new_arr.size < 4 228 | new_arr.push('0') 229 | end 230 | netmask = new_arr.join(".") 231 | end 232 | return netmask 233 | end 234 | 235 | Facter.add(:nic_info) do 236 | confine :kernel => 'Linux' 237 | setcode do 238 | nic_res = get_ip_for_linux() 239 | nic_res = check_mac(nic_res) 240 | nic_res = JSON.dump(nic_res) 241 | end 242 | end 243 | 244 | Facter.add(:nic_info) do 245 | confine :kernel => 'windows' 246 | setcode do 247 | nic_res = get_ip_for_win() 248 | nic_res = check_mac(nic_res) 249 | nic_res = JSON.dump(nic_res) 250 | end 251 | end 252 | -------------------------------------------------------------------------------- /assets_report/lib/facter/raid_adaptor.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift(File.dirname(__FILE__)) unless $LOAD_PATH.include?(File.dirname(__FILE__)) 2 | require "rubygems" 3 | require 'json' 4 | #require_relative 'utils' 5 | require 'utils' 6 | 7 | def merge_response(left, right) 8 | response = {} 9 | left.each do |k, v| 10 | response[k] = left[k].merge(right[k]) if right.has_key?(k) 11 | end 12 | return response 13 | end 14 | 15 | 16 | def mega_raid_pattern_match(needle) 17 | grep_pattern = ['Product Name', 'Serial No', 'Memory Size'] 18 | grep_pattern.each do |pattern| 19 | return true if needle.start_with?(pattern) 20 | end 21 | return false 22 | end 23 | 24 | 25 | 26 | def mega_get_raid_adaptor(cmd) 27 | 28 | key_map = { 29 | 'Product Name' => 'model', 30 | 'Serial No' => 'sn', 31 | 'Memory Size' => 'memory_size', 32 | } 33 | 34 | response = {} 35 | pair_sequence = [] 36 | 37 | metric_from_megacli = Utils.facter_exec(cmd) 38 | 39 | if metric_from_megacli.strip.empty? 40 | return {} 41 | else 42 | filted_raid_result = metric_from_megacli.split("\n").select do |line| 43 | mega_raid_pattern_match(line) 44 | end 45 | end 46 | 47 | if filted_raid_result.empty? 48 | return {} 49 | end 50 | 51 | filted_raid_result.each do |line| 52 | key, value = line.split(':') 53 | pair_sequence.push([key.strip, value.strip]) 54 | end 55 | 56 | first_flag = pair_sequence[0][0] 57 | 58 | element = {} 59 | adaptor_count = -1 60 | pair_sequence_size = pair_sequence.size() 61 | pair_sequence.each_with_index do |pair, idx| 62 | key, value = pair 63 | 64 | next if not key_map.has_key?(key.strip) 65 | 66 | if key == first_flag 67 | element[key_map[key]] = value 68 | elsif (idx+1) == pair_sequence_size or pair_sequence[idx+1][0] == first_flag 69 | element[key_map[key]] = value 70 | adaptor_count += 1 71 | response['adaptor_' << adaptor_count.to_s] = element 72 | element = {} 73 | else 74 | element[key_map[key]] = value 75 | end 76 | 77 | end 78 | 79 | return response 80 | end 81 | 82 | 83 | def hpcli_get_raid_adaptor(cmd) 84 | 85 | response = {} 86 | output = Utils.facter_exec(cmd) 87 | 88 | if not output.empty? 89 | idx = -1 90 | output.split("\n").each do |line| 91 | m = /^(Smart Array.*)in Slot.*sn:(.*)$/.match(line) 92 | next if not m 93 | response["adaptor_#{idx+1}"] = { 94 | 'memory_size' => 0, 95 | 'model' => m[1].strip, 96 | 'sn' => m[2].strip, 97 | } 98 | 99 | end 100 | end 101 | return response 102 | end 103 | 104 | 105 | Facter.add(:raid_adaptor) do 106 | confine :kernel => 'Linux' 107 | setcode do 108 | 109 | response = {} 110 | 111 | if Facter.value(:manufacturer) =~ /.*HP.*/i # ---------------- 112 | cli = Utils.hpacucli_for_linux 113 | cmd = "#{cli} ctrl all show config" 114 | 115 | if File.exist?(cli) 116 | response = hpcli_get_raid_adaptor(cmd) 117 | end 118 | 119 | else # ---------------- 120 | 121 | cli = Utils.megacli_for_linux 122 | cmd = "#{cli} -AdpAllInfo -aALL -Nolog" 123 | if File.exist?(cli) 124 | response = mega_get_raid_adaptor(cmd) 125 | end 126 | 127 | end # ---------------- 128 | 129 | JSON.dump(response) 130 | end 131 | end 132 | 133 | 134 | Facter.add(:raid_adaptor) do 135 | confine :kernel => 'windows' 136 | setcode do 137 | 138 | response = {} 139 | 140 | if Facter.value(:manufacturer) =~ /.*HP.*/i # ---------------- 141 | cli = Utils.hpacucli_for_win 142 | cmd = "#{cli} ctrl all show config" 143 | 144 | if File.exist?(cli) 145 | response = hpcli_get_raid_adaptor(cmd) 146 | end 147 | 148 | else # ---------------- 149 | cli = Utils.megacli_for_win 150 | cmd = "#{cli} -AdpAllInfo -aALL" 151 | 152 | if File.exist?(cli) 153 | response = mega_get_raid_adaptor(cmd) 154 | end 155 | end # ---------------- 156 | 157 | JSON.dump(response) 158 | 159 | end 160 | end 161 | 162 | -------------------------------------------------------------------------------- /assets_report/lib/facter/raid_adaptor_count.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift(File.dirname(__FILE__)) unless $LOAD_PATH.include?(File.dirname(__FILE__)) 2 | require "rubygems" 3 | require 'json' 4 | #require_relative 'utils' 5 | require 'utils' 6 | 7 | def hpcli_get_raid_adaptor_count(cmd) 8 | response = 0 9 | output = Utils.facter_exec(cmd) 10 | if not output.empty? 11 | output.split("\n").each do |line| 12 | m = line.match(/Smart Array.*Slot.*/) 13 | response += 1 if m 14 | end 15 | end 16 | return response 17 | end 18 | 19 | Facter.add(:raid_adaptor_count) do 20 | confine :kernel => 'Linux' 21 | setcode do 22 | 23 | response = 0 24 | 25 | if Facter.value(:manufacturer) =~ /.*HP.*/i 26 | cli = Utils.hpacucli_for_linux 27 | cmd = "#{cli} ctrl all show config" 28 | response = hpcli_get_raid_adaptor_count(cmd) if File.exist?(cli) 29 | else 30 | 31 | cli = Utils.megacli_for_linux 32 | cmd = "#{cli} -adpCount -Nolog|grep Controller" 33 | 34 | if File.exist?(cli) 35 | result = Utils.facter_exec(cmd) 36 | if not result.strip.empty? 37 | key, value = result.split(":") 38 | response = value.strip.chomp('.') 39 | end 40 | end 41 | 42 | end 43 | 44 | response 45 | end 46 | end 47 | 48 | 49 | Facter.add(:raid_adaptor_count) do 50 | confine :kernel => 'windows' 51 | 52 | setcode do 53 | 54 | response = 0 55 | 56 | if Facter.value(:manufacturer) =~ /.*HP.*/i 57 | cli = Utils.hpacucli_for_win 58 | cmd = "#{cli} ctrl all show config" 59 | response = hpcli_get_raid_adaptor_count(cmd) if File.exist?(cli) 60 | 61 | else 62 | 63 | cli = Utils.megacli_for_win 64 | cmd = "#{cli} -adpCount" 65 | if File.exist?(cli) 66 | result = Utils.facter_exec(cmd) 67 | if not result.strip.empty? 68 | result.split("\n").each do |line| 69 | next if line.strip.empty? 70 | key, value = line.split(":") 71 | 72 | next unless key.strip == "Controller Count" 73 | response = value.strip.chomp('.') 74 | break 75 | end 76 | end 77 | end 78 | end 79 | response 80 | end 81 | end 82 | 83 | -------------------------------------------------------------------------------- /assets_report/lib/facter/raid_type.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift(File.dirname(__FILE__)) unless $LOAD_PATH.include?(File.dirname(__FILE__)) 2 | require "rubygems" 3 | require 'json' 4 | require 'utils' 5 | #require_relative 'utils' 6 | 7 | def mega_raid_type_pattern_match(needle) 8 | grep_pattern = ['RAID Level'] 9 | grep_pattern.each do |pattern| 10 | return true if needle.start_with?(pattern) 11 | end 12 | return false 13 | end 14 | 15 | def mega_get_raid_type(cmd) 16 | 17 | response = [] 18 | raid_type_result = Utils.facter_exec(cmd) 19 | 20 | if raid_type_result.strip.empty? 21 | return response 22 | else 23 | filted_raid_type_result = raid_type_result.split("\n").select do |line| 24 | mega_raid_type_pattern_match(line) 25 | end 26 | end 27 | filted_raid_type_result.each do |line| 28 | key, value = line.split(':') 29 | response.push(value.strip) 30 | end 31 | 32 | return response 33 | end 34 | 35 | def hpcli_get_raid_type(cmd) 36 | 37 | response = [] 38 | 39 | raid_type_result = Utils.facter_exec(cmd) 40 | 41 | if not raid_type_result.empty? 42 | raid_type_result.split("\n").each do |line| 43 | m = line.match(/logicaldrive.*RAID.*/) 44 | response.push(m[0]) if m 45 | end 46 | end 47 | 48 | return response 49 | end 50 | 51 | 52 | Facter.add(:raid_type) do 53 | confine :kernel => 'Linux' 54 | setcode do 55 | 56 | response = [] 57 | 58 | if Facter.value(:manufacturer) =~ /.*HP.*/i # --------- 59 | 60 | cli = Utils.hpacucli_for_linux 61 | cmd = "#{cli} ctrl all show config" 62 | response = hpcli_get_raid_type(cmd) 63 | 64 | else # --------- 65 | 66 | cli = Utils.megacli_for_linux 67 | cmd = "#{cli} -LDInfo -Lall -aALL -Nolog" 68 | 69 | if File.exist?(cli) 70 | response = mega_get_raid_type(cmd) 71 | end 72 | end # --------- 73 | 74 | if response 75 | response.join(";") 76 | else 77 | "" 78 | end 79 | 80 | end 81 | end 82 | 83 | Facter.add(:raid_type) do 84 | confine :kernel => 'windows' 85 | setcode do 86 | 87 | response = [] 88 | 89 | if Facter.value(:manufacturer) =~ /.*HP.*/i # --------- 90 | cli = Utils.hpacucli_for_win 91 | cmd = "#{cli} ctrl all show config" 92 | response = hpcli_get_raid_type(cmd) 93 | 94 | else 95 | 96 | cli = Utils.megacli_for_win 97 | cmd = "#{cli} -LDInfo -Lall -aALL" 98 | 99 | if File.exist?(cli) 100 | response = mega_get_raid_type(cmd) 101 | end 102 | end 103 | 104 | if response 105 | response.join(";") 106 | else 107 | "" 108 | end 109 | 110 | end 111 | end 112 | 113 | 114 | -------------------------------------------------------------------------------- /assets_report/lib/facter/ram.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift(File.dirname(__FILE__)) unless $LOAD_PATH.include?(File.dirname(__FILE__)) 2 | require "rubygems" 3 | require 'pp' 4 | require 'json' 5 | require 'utils' 6 | 7 | def dmi_get_ram(cmd) 8 | 9 | ram_slot = [] 10 | 11 | key_map = { 12 | 'Size' => 'capacity', 13 | 'Serial Number' => 'sn', 14 | 'Type' => 'model', 15 | 'Manufacturer' => 'manufactory', 16 | 'Locator' => 'slot', 17 | } 18 | 19 | output = Utils.facter_exec(cmd) 20 | devices = output.split('Memory Device') 21 | 22 | devices.each do |d| 23 | next if d.strip.empty? 24 | segment = {} 25 | d.strip.split("\n\t").each do |line| 26 | key, value = line.strip.split(":") 27 | if key_map.has_key?(key.strip) 28 | if key.strip == 'Size' 29 | if value.include?("MB") 30 | segment[key_map['Size']] = value.chomp("MB").strip.to_i / 1024.0 # unit GB 31 | else 32 | segment[key_map['Size']] = value.chomp("GB").strip.to_i # unit GB 33 | end 34 | else 35 | segment[key_map[key.strip]] = value ? value.strip : '' 36 | end 37 | end 38 | end 39 | 40 | ram_slot.push(segment) unless segment.empty? 41 | end 42 | 43 | return ram_slot 44 | 45 | end 46 | 47 | Facter.add("ram") do 48 | confine :kernel => "Linux" 49 | setcode do 50 | 51 | ram_slot = [] 52 | cmd = "dmidecode -q -t 17 2>/dev/null" 53 | ram_slot = dmi_get_ram(cmd) 54 | 55 | JSON.dump(ram_slot) 56 | 57 | end 58 | end 59 | 60 | 61 | Facter.add("ram") do 62 | confine :kernel => 'windows' 63 | setcode do 64 | 65 | ram_slot = [] 66 | 67 | if Facter.value(:manufacturer) =~ /.*HP.*/i 68 | cli = 'C:\assets_report\dmidecode.exe' 69 | cmd = "#{cli} -q -t 17" 70 | ram_slot = dmi_get_ram(cmd) if File.exist?(cli) 71 | 72 | else 73 | 74 | require 'facter/util/wmi' 75 | Facter::Util::WMI.execquery("select * from Win32_PhysicalMemory").each do | item | 76 | 77 | if item.DeviceLocator 78 | slot = item.DeviceLocator.strip 79 | else 80 | slot = '' 81 | end 82 | 83 | if item.PartNumber 84 | model = item.PartNumber.strip 85 | else 86 | model = '' 87 | end 88 | 89 | if item.SerialNumber 90 | sn = item.SerialNumber.strip 91 | else 92 | sn = '' 93 | end 94 | 95 | if item.Manufacturer 96 | manufactory = item.Manufacturer.strip 97 | else 98 | manufactory = '' 99 | end 100 | 101 | ram_slot.push({ 102 | 'capacity' => item.Capacity.to_i / (1024**3), # unit GB 103 | 'slot' => slot, 104 | 'model' => model, 105 | 'sn' => sn, 106 | 'manufactory' => manufactory, 107 | }) 108 | 109 | end 110 | end 111 | 112 | JSON.dump(ram_slot) 113 | 114 | end 115 | end 116 | -------------------------------------------------------------------------------- /assets_report/lib/facter/setup_time.rb: -------------------------------------------------------------------------------- 1 | require "rubygems" 2 | 3 | 4 | Facter.add(:setuptime) do 5 | confine :kernel => 'Linux' 6 | setcode do 7 | setuptime_file = '/root/anaconda-ks.cfg' 8 | file = File.open(setuptime_file) 9 | 10 | if not File.exist?(setuptime_file) 11 | setuptime = "" 12 | else 13 | setuptime = file.stat.ctime.to_i 14 | end 15 | end 16 | end 17 | 18 | Facter.add(:setuptime) do 19 | confine :kernel => 'windows' 20 | setcode do 21 | 22 | setuptime_file = 'C:\Intel\Logs\IntelChipset.log' 23 | file = File.open(setuptime_file) 24 | 25 | if not File.exist?(setuptime_file) 26 | setuptime = "" 27 | else 28 | setuptime = file.stat.ctime.to_i 29 | end 30 | end 31 | 32 | end 33 | -------------------------------------------------------------------------------- /assets_report/lib/facter/sn.rb: -------------------------------------------------------------------------------- 1 | # -*- encoding : utf-8 -*- 2 | 3 | require 'rbconfig' 4 | require 'rubygems' 5 | 6 | def win_sn 7 | output = `wmic bios get serialnumber /VALUE` 8 | sn = '' 9 | output.split("\n").each do |line| 10 | if line.start_with?("SerialNumber") 11 | sn = line.split("=")[1] 12 | break 13 | end 14 | end 15 | return sn 16 | end 17 | 18 | def linux_sn 19 | sn = '' 20 | output = `dmidecode -t 1|grep Serial` 21 | output.split("\n").each do |line| 22 | sn = line.split(":")[1].strip 23 | break 24 | end 25 | 26 | return sn 27 | end 28 | 29 | Facter.add(:sn) do 30 | setcode do 31 | 32 | case RbConfig::CONFIG['host_os'] 33 | when /cygwin|mswin|mingw|bccwin|wince|emx|windows/i 34 | win_sn 35 | when /linux|arch/i 36 | linux_sn 37 | end 38 | end 39 | end 40 | 41 | 42 | -------------------------------------------------------------------------------- /assets_report/lib/facter/utils.rb: -------------------------------------------------------------------------------- 1 | require "rubygems" 2 | 3 | module Utils 4 | 5 | def self.get_facter_version 6 | version = Facter.value('facterversion') 7 | major = version.split('.')[0] 8 | return major.to_i 9 | end 10 | 11 | def self.facter_exec(cmd) 12 | result = '' 13 | if Utils.get_facter_version < 2 14 | result = Facter::Util::Resolution.exec(cmd) 15 | else 16 | result = Facter::Core::Execution.exec(cmd) 17 | end 18 | return result 19 | end 20 | 21 | def self.megacli_for_win 22 | if Facter.value(:architecture) == "x64" 23 | cli = 'C:\assets_report\MegaCli64.exe' 24 | else 25 | cli = 'C:\assets_report\MegaCli.exe' 26 | end 27 | return cli 28 | end 29 | 30 | def self.megacli_for_linux 31 | return '/opt/MegaRAID/MegaCli/MegaCli64' 32 | end 33 | 34 | def self.hpacucli_for_win 35 | return 'C:\assets_report\Compaq\Hpacucli\Bin\hpacucli.exe' 36 | end 37 | 38 | def self.hpacucli_for_linux 39 | 40 | hpssacli = '/opt/hp/hpssacli/bld/hpssacli' 41 | hpacucli = '/opt/compaq/hpacucli/bld/hpacucli' 42 | 43 | if File.exist?(hpssacli) 44 | return hpssacli 45 | else 46 | return hpacucli 47 | end 48 | 49 | end 50 | 51 | end 52 | -------------------------------------------------------------------------------- /assets_report/lib/puppet/reports/assets_report.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift(File.dirname(__FILE__)) unless $LOAD_PATH.include?(File.dirname(__FILE__)) 2 | require "rubygems" 3 | require 'puppet' 4 | require 'puppet/network/http_pool' 5 | require 'uri' 6 | require 'yaml' 7 | require 'pathname' 8 | require 'json' 9 | require 'net/http' 10 | require 'pp' 11 | require 'auth' 12 | 13 | Puppet::Reports.register_report(:assets_report) do 14 | 15 | desc <<-DESC 16 | Send reports via HTTP or HTTPS. This report processor submits reports as 17 | POST requests to the address in the settings. The body of each POST 18 | request is the YAML dump of a Puppet::Transaction::Report object, and the 19 | Content-Type is set as `application/x-yaml`. 20 | DESC 21 | 22 | $setting_file = 'report_setting.yaml' 23 | $fact_dir = Pathname(Puppet[:vardir]) + Pathname('yaml') + Pathname('facts') 24 | 25 | class ReportCache 26 | def initialize(fact_file, enable_cache) 27 | @fact_file = fact_file 28 | @enable_cache = enable_cache 29 | end 30 | 31 | def get_cache_file 32 | base_name = File.basename(@fact_file) 33 | return $fact_dir + "cache.#{base_name}" 34 | end 35 | 36 | def write_cache(content) 37 | cache_file = get_cache_file() 38 | File.open(cache_file, 'w+') do |fp| 39 | fp.write(content.strip) 40 | end 41 | end 42 | 43 | def cached?(data) 44 | # data is a runy hash of report_data 45 | unless @enable_cache 46 | return false 47 | end 48 | cache_file = get_cache_file() 49 | if not File.exist?(cache_file) 50 | return false 51 | end 52 | 53 | File.open(cache_file, 'r') do |fp| 54 | cached_content = fp.read() 55 | if data == JSON.parse(cached_content) 56 | return true 57 | else 58 | return false 59 | end 60 | end 61 | end 62 | end 63 | 64 | 65 | 66 | class NIC 67 | def self.not_hardware?(nic_name) 68 | black_list = ['lo', 'tun'] 69 | black_list.each do |e| 70 | if Regexp.new(e).match(nic_name) 71 | return true 72 | end 73 | end 74 | return false 75 | end 76 | 77 | def self.is_hardware?(nic_name) 78 | hw_names = ['em', 'eth', 'p', 'lan', 'Local'] 79 | 80 | hw_names.each do |e| 81 | if nic_name.start_with?(e) 82 | return true 83 | end 84 | end 85 | return false 86 | end 87 | end 88 | 89 | 90 | def process 91 | 92 | cert_name = self.name 93 | cert_name_tag = "__assets_report__#{cert_name}__" 94 | setting_file_path = Pathname.new(File.dirname(__FILE__)) + $setting_file 95 | 96 | unless File.exist?(setting_file_path) 97 | Puppet.err "#{cert_name_tag} setting file is not exist: #{setting_file_path} " 98 | end 99 | 100 | setting = YAML.load_file(setting_file_path) 101 | url = URI.parse(setting[:report_url]) 102 | auth_required = setting[:auth_required] 103 | user = setting[:user] 104 | passwd = setting[:passwd] 105 | enable_cache = setting[:enable_cache] 106 | 107 | headers = { 'Content-Type' => 'application/json; charset=UTF-8' } 108 | options = {} 109 | 110 | fact_file = $fact_dir + Pathname("#{self.name}.yaml") 111 | if not fact_file.exist? 112 | Puppet.err "#{cert_name_tag} Fact file is not exist: #{fact_file}" 113 | return false 114 | end 115 | 116 | if auth_required 117 | au = AuthUrl.new(user, passwd, url.path) 118 | report_path = au.build_auth_url() 119 | else 120 | report_path = url.path 121 | end 122 | 123 | fact_data = YAML::load_file(fact_file) 124 | 125 | ################################################ 126 | # for ram 127 | ################################################ 128 | ram_slot_hash = {} 129 | fact_ram_slot = fact_data.values.fetch('ram', '[]') 130 | total_ram_size = 0 131 | 132 | JSON.load(fact_ram_slot).each do |e| 133 | size = Integer(e['capacity']) if Integer(e['capacity']) rescue false # unit GB 134 | if not size 135 | size = 0 136 | end 137 | ram_slot_hash[e['slot']] = 138 | { 139 | 'sn' => e['sn'], 140 | 'model' => e['model'], 141 | 'manufactory' => e['manufactory'], 142 | 'capacity' => size, 143 | } 144 | total_ram_size += size 145 | end 146 | # for windows 2003 and below 147 | if 0 == total_ram_size 148 | total_ram_size = fact_data.values.fetch('memorysize_mb', '0').to_i / 1024.0 149 | # if ram size is below 1G, we can not round it, otherwise it will be zero. 150 | if total_ram_size > 1 151 | total_ram_size = total_ram_size.round 152 | end 153 | end 154 | 155 | 156 | ################################################ 157 | # for nic 158 | ################################################ 159 | nic_interface = fact_data.values.fetch('interfaces', '') 160 | nic_bonding_data = fact_data.values.fetch('bonding', '{}') 161 | 162 | nic_bonding_map = JSON.parse(nic_bonding_data) 163 | nic_interface = fact_data.values.fetch('interfaces', '') 164 | nic_count = 0 165 | nic_hash = {} 166 | 167 | if not nic_interface.empty? 168 | nic_res = fact_data.values.fetch('nic_info') 169 | nic_hash = JSON.parse(nic_res) 170 | nic_count = nic_hash.length 171 | else 172 | # on some machine Facter do not provide fact interfaces 173 | nic_count = 1 174 | nic_hash['local'] = {} 175 | nic_hash['local']['ipaddress'] = fact_data.values.fetch('ipaddress','') 176 | nic_hash['local']['macaddress'] = fact_data.values.fetch('macaddress', '') 177 | nic_hash['local']['netmask'] = fact_data.values.fetch('netmask', '') 178 | nic_hash['local']['network'] = fact_data.values.fetch('network', '') 179 | nic_hash['local']['model'] = '' 180 | nic_hash['local']['hardware'] = 1 181 | 182 | end 183 | 184 | ################################################ 185 | # for disk 186 | ################################################ 187 | raid_adaptor_count = fact_data.values.fetch('raid_adaptor_count', '0').to_i 188 | 189 | physical_disk_string = fact_data.values.fetch('physical_disk_driver', '[]') 190 | physical_disk_driver = JSON.parse(physical_disk_string) 191 | 192 | 193 | 194 | ################################################ 195 | # for raid adaptor 196 | ################################################ 197 | raid_adaptor_hash = {} 198 | raid_adaptor_data = fact_data.values.fetch('raid_adaptor', '{}') 199 | JSON.parse(raid_adaptor_data).each do |k, v| 200 | raid_adaptor_hash[k] = {} 201 | v.each_key do |ik| 202 | raid_adaptor_hash[k]['model'] = v["model"] 203 | raid_adaptor_hash[k]['sn'] = v["sn"] 204 | raid_adaptor_hash[k]['memory_size'] = v["memory_size"] 205 | #raid_adaptor_hash[k]['raid_type'] = v["RAID Level"] 206 | end 207 | end 208 | 209 | 210 | report_data = { 211 | 'os_type' => fact_data.values.fetch('kernel', '').strip, 212 | 'os_distribution' => fact_data.values.fetch('operatingsystem', '').strip, 213 | 'os_release' => fact_data.values.fetch('operatingsystemrelease', '').strip, 214 | 'not_modify' => 0, 215 | 'setuptime' => fact_data.values.fetch('setuptime',''), 216 | 'sn' => fact_data.values.fetch('serialnumber', '').strip, 217 | 'manufactory' => fact_data.values.fetch('manufacturer', '').strip, 218 | 'productname' => fact_data.values.fetch('productname','').strip, 219 | 'model' => fact_data.values.fetch('productname', '').strip, 220 | 221 | 'cpu_count' => fact_data.values.fetch('physicalprocessorcount', ''), 222 | 'cpu_core_count' => fact_data.values.fetch('cpu_core_count', ''), 223 | 'cpu_model' => fact_data.values.fetch('processor0', '').strip, 224 | 225 | 'nic_count' => nic_count, 226 | 'nic' => nic_hash, 227 | 228 | 'raid_adaptor_count' => raid_adaptor_count, 229 | 'raid_adaptor' => raid_adaptor_hash, 230 | 'raid_type' => fact_data.values.fetch('raid_type', ''), 231 | 232 | 'physical_disk_driver' => physical_disk_driver, 233 | 'ram_size' => total_ram_size, 234 | 'ram_slot' => ram_slot_hash, 235 | 'certname' => self.name, 236 | } 237 | 238 | #PP.pp(report_data) 239 | 240 | report_data_in_json = {} 241 | cached_flag = false 242 | cache = ReportCache.new(fact_file, enable_cache) 243 | 244 | if cache.cached?(report_data) 245 | Puppet.info "Report content is not modified" 246 | report_data_in_json = JSON.dump({'not_modify' => 1, 'certname' => self.name}) 247 | cached_flag = true 248 | else 249 | Puppet.info "Report content is modified" 250 | report_data_in_json = JSON.dump(report_data) 251 | end 252 | 253 | #Puppet.info "report_path: #{report_path}" 254 | #Puppet.info report_path 255 | conn = Puppet::Network::HttpPool.http_instance(url.host, url.port, use_ssl=false, verify_peer=false) 256 | response = conn.post(report_path, report_data_in_json, headers, options) 257 | 258 | if response.kind_of?(Net::HTTPSuccess) 259 | begin 260 | cache.write_cache(report_data_in_json) unless cached_flag 261 | rescue Exception => e 262 | Puppet.err "Write report cache failed #{cert_name_tag}: #{e.message}" 263 | end 264 | Puppet.info "Header: #{response.code}" 265 | Puppet.info "Body: #{response.body}" 266 | else 267 | response.each {|k, v| Puppet.err "#{cert_name_tag} Header: #{k}: #{v}" } 268 | Puppet.err "#{cert_name_tag} #{response.body}" 269 | Puppet.err "Unable to submit #{cert_name_tag} report to #{url} [#{response.code}] #{response.msg}" 270 | 271 | end 272 | end 273 | 274 | end 275 | -------------------------------------------------------------------------------- /assets_report/lib/puppet/reports/auth.rb: -------------------------------------------------------------------------------- 1 | # encoding: UTF-8 2 | 3 | require 'openssl' 4 | require 'digest' 5 | require 'uri' 6 | 7 | class AuthUrl 8 | 9 | ###Auth code### 10 | 11 | end 12 | -------------------------------------------------------------------------------- /assets_report/lib/puppet/reports/report_setting.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | :report_url : 'http://localhost/api/v1.0/asset/report/' 3 | :auth_required : false 4 | :user : 'user' 5 | :passwd : 'passwd' 6 | :enable_cache : false 7 | -------------------------------------------------------------------------------- /assets_report/manifests/init.pp: -------------------------------------------------------------------------------- 1 | class assets_report { 2 | 3 | if $kernel == 'windows' { 4 | 5 | file {'assets_report_files': 6 | path => 'C:\\assets_report', 7 | source => "puppet:///modules/assets_report/assets_report", 8 | ensure => directory, 9 | purge => true, 10 | source_permissions => ignore, 11 | recurse => true, 12 | owner => "Administrators", 13 | group => "Administrators", 14 | } 15 | 16 | } else { 17 | 18 | file {"assets_report_files": 19 | path => '/tmp/assets_report', 20 | source => "puppet:///modules/assets_report/assets_report", 21 | ensure => directory, 22 | recurse => true, 23 | } 24 | 25 | package {"MegaCli": 26 | provider => 'rpm', 27 | source => '/tmp/assets_report/MegaCli-8.07.10-1.noarch.rpm', 28 | ensure => installed, 29 | require => File['assets_report_files'], 30 | allow_virtual => false, 31 | } 32 | 33 | file {"/usr/bin/megacli": 34 | ensure => 'link', 35 | target => '/opt/MegaRAID/MegaCli/MegaCli64', 36 | require => Package['MegaCli'], 37 | } 38 | package {'hpacucli': 39 | provider => 'rpm', 40 | source => '/tmp/assets_report/hpacucli-9.40-12.0.x86_64.rpm', 41 | ensure => installed, 42 | require => File['assets_report_files'], 43 | allow_virtual => false, 44 | install_options => ['--force', '--nodeps'], 45 | } 46 | 47 | package {'hpssacli': 48 | provider => 'rpm', 49 | source => '/tmp/assets_report/hpssacli-2.0-23.0.x86_64.rpm', 50 | ensure => installed, 51 | require => File['assets_report_files'], 52 | allow_virtual => false, 53 | install_options => ['--force', '--nodeps'], 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /docs/server_puppet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AutohomeCorp/Assets_Report/c2484031f0c3e14beb7bf65ff53afba523028d58/docs/server_puppet.png --------------------------------------------------------------------------------