├── .circleci └── config.yml ├── .gitignore ├── .gometalinter.json ├── .promu.yml ├── .travis.yml ├── CHANGELOG.md ├── Dockerfile ├── Gopkg.lock ├── Gopkg.toml ├── LICENSE ├── Makefile ├── NOTICE ├── README.md ├── VERSION ├── gluster-init.sh ├── gluster_client.go ├── main.go ├── main_test.go ├── structs ├── xmlStructs.go └── xmlStructs_test.go └── test ├── gluster_peer_status.xml ├── gluster_volume_heal_info.xml ├── gluster_volume_heal_info_err_node1.xml ├── gluster_volume_heal_info_err_node2.xml ├── gluster_volume_info.xml ├── gluster_volume_list.xml ├── gluster_volume_profile_gv_test_info.xml ├── gluster_volume_profile_gv_test_info_cumulative.xml ├── gluster_volume_quota_list.xml └── gluster_volume_status_all_detail.xml /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | # Golang CircleCI 2.0 configuration file 2 | # 3 | # Check https://circleci.com/docs/2.0/language-go/ for more details 4 | version: 2 5 | jobs: 6 | codespell: 7 | docker: 8 | - image: circleci/python 9 | 10 | steps: 11 | - checkout 12 | - run: sudo pip install codespell 13 | - run: codespell --skip=".git,./vendor" 14 | 15 | workflows: 16 | version: 2 17 | gluster_exporter: 18 | jobs: 19 | - codespell: 20 | filters: 21 | tags: 22 | only: /.*/ 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | *.prof 25 | 26 | # Output of the go coverage tool, specifically when used with LiteIDE 27 | *.out 28 | 29 | # external packages folder 30 | vendor/* 31 | 32 | .idea/ 33 | 34 | gluster_exporter 35 | *.tar.gz 36 | -------------------------------------------------------------------------------- /.gometalinter.json: -------------------------------------------------------------------------------- 1 | { 2 | "Cyclo": 40, 3 | "Deadline": "6m", 4 | "EnableGC": true, 5 | "Exclude": ["Subprocess launching with variable", "Subprocess launched with variable", "Subprocess launching should be audited"], 6 | "Sort": ["linter", "severity", "path", "line"], 7 | "Vendor": true 8 | } 9 | -------------------------------------------------------------------------------- /.promu.yml: -------------------------------------------------------------------------------- 1 | go: 2 | cgo: false 3 | repository: 4 | path: github.com/ofesseler/gluster_exporter 5 | build: 6 | flags: -a -tags 'netgo static_build' 7 | ldflags: | 8 | -s 9 | -X {{repoPath}}/vendor/github.com/prometheus/common/version.Version={{.Version}} 10 | -X {{repoPath}}/vendor/github.com/prometheus/common/version.Revision={{.Revision}} 11 | -X {{repoPath}}/vendor/github.com/prometheus/common/version.Branch={{.Branch}} 12 | -X {{repoPath}}/vendor/github.com/prometheus/common/version.BuildUser={{user}}@{{host}} 13 | -X {{repoPath}}/vendor/github.com/prometheus/common/version.BuildDate={{date "20060102-15:04:05"}} 14 | tarball: 15 | files: 16 | - LICENSE 17 | - NOTICE 18 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | language: go 4 | 5 | go: 6 | - 1.9.x 7 | - 1.10.x 8 | - tip 9 | 10 | script: 11 | - make build 12 | - make gometalinter 13 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # v0.2.7 / 2017-05-09 2 | 3 | * [Fix] Bug #11 Incorrect volume name or error with PR #13 Fix unmarshalling of volume status 4 | * [Feature] #12 Feature/add quota metrics 5 | * [Feature] #9  Add metrics used in promethueus 6 | 7 | # v0.2.6 / 2017-02-16 8 | 9 | * [Feature] PR#8 Adds new Metrics: 10 | - mount_successful: Checks if mountpoints of volumes occur in 'mount' at system 11 | - volume_writeable: Issues Create and Remove file on mounted volume 12 | - heal_info_files_count: adds all files out of sync together. If this is > 0 your gluster is probably out of sync 13 | 14 | # v0.2.5 / 2017-12-14 15 | 16 | * [Feature] Added new metrics exposed by command gluster volume status all details: 17 | - `gluster_node_size_free_bytes` 18 | - `gluster_node_size_total_bytes` 19 | 20 | # v0.2.4 / 2016-12-12 21 | 22 | * [Feature] Adds FOP Metrics. 23 | 24 | # v0.2.3 / 2016-12-05 25 | 26 | * [Feature] Now builds with promu. 27 | * [Feature] `gluster_exporter -version` shows the correct information. 28 | 29 | # v0.2.2 / 2016-11-29 30 | 31 | * [Feature] Added metrics: `brick duration`, `totalRead`, `totalWrite` 32 | * [Feature] Extended README doc 33 | * [Feature] Added status badges for cirlce and travis 34 | * [Fix] A lot of formatting, fixing typos and refactoring. 35 | * [Fix] Fixed warning of golint. 36 | 37 | # v0.1.2 / 2016-11-28 38 | 39 | * [Feature] Exposes new value: `peers_connected`. 40 | * [Fix] Removes label "node". 41 | * [Fix] Refactoring. 42 | 43 | # v0.1.1 / 2016-11-22 44 | 45 | * [Feature] ConstMetrics 46 | * [Feature] Build with promu 47 | * [Feature] vendor.json 48 | * [Fix] Better error messages 49 | 50 | # v0.1.0 / 2016-11-21 51 | 52 | * First version of `gluster_exporter`. 53 | ATM it only runs "gluster volume info --xml" as a command and parses the xml output. 54 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:stretch 2 | MAINTAINER Oliver Fesseler 3 | 4 | EXPOSE 9189 5 | EXPOSE 24007 6 | EXPOSE 24009-24108 7 | 8 | RUN apt-get update && apt-get install -y apt-utils apt-transport-https ca-certificates gnupg2 9 | # Gluster debian Repo 10 | ADD http://download.gluster.org/pub/gluster/glusterfs/3.12/rsa.pub /tmp 11 | RUN apt-key add /tmp/rsa.pub && rm -f /tmp/rsa.pub 12 | 13 | # Add gluster debian repo and update apt 14 | RUN echo "deb https://download.gluster.org/pub/gluster/glusterfs/3.12/LATEST/Debian/stretch/amd64/apt stretch main" > /etc/apt/sources.list.d/gluster.list 15 | RUN apt-get update 16 | 17 | # Install Gluster server 18 | RUN DEBIAN_FRONTEND=noninteractive apt-get -y install glusterfs-server 19 | 20 | # Clean 21 | RUN apt-get clean 22 | 23 | 24 | # Create gluster volume, start gluster service and gluster_exporter 25 | RUN mkdir -p /data 26 | RUN mkdir -p /mnt/data 27 | RUN mkdir -p /mnt/gv_test 28 | 29 | COPY gluster-init.sh /usr/bin/gluster-init.sh 30 | RUN chmod a+x /usr/bin/gluster-init.sh 31 | 32 | # Copy gluster_exporter 33 | COPY gluster_exporter /usr/bin/gluster_exporter 34 | 35 | #RUN /usr/bin/gluster-init.sh 36 | ENTRYPOINT /usr/bin/gluster-init.sh 37 | #ENTRYPOINT /bin/bash 38 | -------------------------------------------------------------------------------- /Gopkg.lock: -------------------------------------------------------------------------------- 1 | # This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. 2 | 3 | 4 | [[projects]] 5 | branch = "master" 6 | digest = "1:315c5f2f60c76d89b871c73f9bd5fe689cad96597afd50fb9992228ef80bdd34" 7 | name = "github.com/alecthomas/template" 8 | packages = [ 9 | ".", 10 | "parse", 11 | ] 12 | pruneopts = "UT" 13 | revision = "a0175ee3bccc567396460bf5acd36800cb10c49c" 14 | 15 | [[projects]] 16 | branch = "master" 17 | digest = "1:c198fdc381e898e8fb62b8eb62758195091c313ad18e52a3067366e1dda2fb3c" 18 | name = "github.com/alecthomas/units" 19 | packages = ["."] 20 | pruneopts = "UT" 21 | revision = "2efee857e7cfd4f3d0138cc3cbb1b4966962b93a" 22 | 23 | [[projects]] 24 | branch = "master" 25 | digest = "1:d6afaeed1502aa28e80a4ed0981d570ad91b2579193404256ce672ed0a609e0d" 26 | name = "github.com/beorn7/perks" 27 | packages = ["quantile"] 28 | pruneopts = "UT" 29 | revision = "3a771d992973f24aa725d07868b467d1ddfceafb" 30 | 31 | [[projects]] 32 | digest = "1:15042ad3498153684d09f393bbaec6b216c8eec6d61f63dff711de7d64ed8861" 33 | name = "github.com/golang/protobuf" 34 | packages = ["proto"] 35 | pruneopts = "UT" 36 | revision = "b4deda0973fb4c70b50d226b1af49f3da59f5265" 37 | version = "v1.1.0" 38 | 39 | [[projects]] 40 | digest = "1:ff5ebae34cfbf047d505ee150de27e60570e8c394b3b8fdbb720ff6ac71985fc" 41 | name = "github.com/matttproud/golang_protobuf_extensions" 42 | packages = ["pbutil"] 43 | pruneopts = "UT" 44 | revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c" 45 | version = "v1.0.1" 46 | 47 | [[projects]] 48 | digest = "1:d14a5f4bfecf017cb780bdde1b6483e5deb87e12c332544d2c430eda58734bcb" 49 | name = "github.com/prometheus/client_golang" 50 | packages = [ 51 | "prometheus", 52 | "prometheus/promhttp", 53 | ] 54 | pruneopts = "UT" 55 | revision = "c5b7fccd204277076155f10851dad72b76a49317" 56 | version = "v0.8.0" 57 | 58 | [[projects]] 59 | branch = "master" 60 | digest = "1:2d5cd61daa5565187e1d96bae64dbbc6080dacf741448e9629c64fd93203b0d4" 61 | name = "github.com/prometheus/client_model" 62 | packages = ["go"] 63 | pruneopts = "UT" 64 | revision = "5c3871d89910bfb32f5fcab2aa4b9ec68e65a99f" 65 | 66 | [[projects]] 67 | branch = "master" 68 | digest = "1:e19679d216d9761aa37695c513de1a893fb8bbdc5732eccabc84d036f33b9ce5" 69 | name = "github.com/prometheus/common" 70 | packages = [ 71 | "expfmt", 72 | "internal/bitbucket.org/ww/goautoneg", 73 | "log", 74 | "model", 75 | "version", 76 | ] 77 | pruneopts = "UT" 78 | revision = "7600349dcfe1abd18d72d3a1770870d9800a7801" 79 | 80 | [[projects]] 81 | branch = "master" 82 | digest = "1:8c49953a1414305f2ff5465147ee576dd705487c35b15918fcd4efdc0cb7a290" 83 | name = "github.com/prometheus/procfs" 84 | packages = [ 85 | ".", 86 | "internal/util", 87 | "nfs", 88 | "xfs", 89 | ] 90 | pruneopts = "UT" 91 | revision = "05ee40e3a273f7245e8777337fc7b46e533a9a92" 92 | 93 | [[projects]] 94 | digest = "1:d867dfa6751c8d7a435821ad3b736310c2ed68945d05b50fb9d23aee0540c8cc" 95 | name = "github.com/sirupsen/logrus" 96 | packages = ["."] 97 | pruneopts = "UT" 98 | revision = "3e01752db0189b9157070a0e1668a620f9a85da2" 99 | version = "v1.0.6" 100 | 101 | [[projects]] 102 | branch = "master" 103 | digest = "1:3f3a05ae0b95893d90b9b3b5afdb79a9b3d96e4e36e099d841ae602e4aca0da8" 104 | name = "golang.org/x/crypto" 105 | packages = ["ssh/terminal"] 106 | pruneopts = "UT" 107 | revision = "c126467f60eb25f8f27e5a981f32a87e3965053f" 108 | 109 | [[projects]] 110 | branch = "master" 111 | digest = "1:c7b59634b5cb02e29639e393d32e9d6c8bc10819535f5e4c7545ef6f321eebd6" 112 | name = "golang.org/x/sys" 113 | packages = [ 114 | "unix", 115 | "windows", 116 | "windows/registry", 117 | "windows/svc/eventlog", 118 | ] 119 | pruneopts = "UT" 120 | revision = "e072cadbbdc8dd3d3ffa82b8b4b9304c261d9311" 121 | 122 | [[projects]] 123 | digest = "1:c06d9e11d955af78ac3bbb26bd02e01d2f61f689e1a3bce2ef6fb683ef8a7f2d" 124 | name = "gopkg.in/alecthomas/kingpin.v2" 125 | packages = ["."] 126 | pruneopts = "UT" 127 | revision = "947dcec5ba9c011838740e680966fd7087a71d0d" 128 | version = "v2.2.6" 129 | 130 | [solve-meta] 131 | analyzer-name = "dep" 132 | analyzer-version = 1 133 | input-imports = [ 134 | "github.com/prometheus/client_golang/prometheus", 135 | "github.com/prometheus/client_golang/prometheus/promhttp", 136 | "github.com/prometheus/common/log", 137 | "github.com/prometheus/common/version", 138 | "gopkg.in/alecthomas/kingpin.v2", 139 | ] 140 | solver-name = "gps-cdcl" 141 | solver-version = 1 142 | -------------------------------------------------------------------------------- /Gopkg.toml: -------------------------------------------------------------------------------- 1 | # Gopkg.toml example 2 | # 3 | # Refer to https://golang.github.io/dep/docs/Gopkg.toml.html 4 | # for detailed Gopkg.toml documentation. 5 | # 6 | # required = ["github.com/user/thing/cmd/thing"] 7 | # ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] 8 | # 9 | # [[constraint]] 10 | # name = "github.com/user/project" 11 | # version = "1.0.0" 12 | # 13 | # [[constraint]] 14 | # name = "github.com/user/project2" 15 | # branch = "dev" 16 | # source = "github.com/myfork/project2" 17 | # 18 | # [[override]] 19 | # name = "github.com/x/y" 20 | # version = "2.4.0" 21 | # 22 | # [prune] 23 | # non-go = false 24 | # go-tests = true 25 | # unused-packages = true 26 | 27 | 28 | [[constraint]] 29 | name = "github.com/prometheus/client_golang" 30 | version = "0.8.0" 31 | 32 | [[constraint]] 33 | branch = "master" 34 | name = "github.com/prometheus/common" 35 | 36 | [[constraint]] 37 | name = "gopkg.in/alecthomas/kingpin.v2" 38 | version = "2.2.6" 39 | 40 | [prune] 41 | go-tests = true 42 | unused-packages = true 43 | -------------------------------------------------------------------------------- /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 [2016] [Oliver Fesseler] 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. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | GO ?= go 2 | GOPATH := $(firstword $(subst :, ,$(shell $(GO) env GOPATH))) 3 | pkgs = $(shell $(GO) list ./... | grep -v /vendor/) 4 | PROMU ?= $(GOPATH)/bin/promu 5 | GODEP ?= $(GOPATH)/bin/dep 6 | GOLINTER ?= $(GOPATH)/bin/gometalinter 7 | BIN_DIR ?= $(shell pwd):x 8 | TARGET ?= gluster_exporter 9 | 10 | info: 11 | @echo "build: Go build" 12 | @echo "docker: build and run in docker container" 13 | @echo "gometalinter: run some linting checks" 14 | @echo "gotest: run go tests and reformats" 15 | 16 | build: depcheck $(PROMU) gotest 17 | @echo ">> building binaries" 18 | @$(PROMU) build 19 | 20 | docker: gotest build 21 | docker build -t gluster-exporter-test . 22 | docker run --rm --privileged=true -p 9189:9189 -p 24007:24007 -p 24009-24108:24009-24108/tcp -i -v gluster-test:/data gluster-exporter-test 23 | 24 | gotest: vet format 25 | @echo ">> running tests" 26 | @$(GO) test -short $(pkgs) 27 | 28 | format: 29 | @echo ">> formatting code" 30 | @$(GO) fmt $(pkgs) 31 | 32 | vet: 33 | @echo ">> vetting code" 34 | @$(GO) vet $(pkgs) 35 | 36 | $(GOPATH)/bin/promu promu: 37 | @GOOS=$(shell uname -s | tr A-Z a-z) \ 38 | GOARCH=$(subst x86_64,amd64,$(patsubst i%86,386,$(shell uname -m))) \ 39 | $(GO) get -u github.com/prometheus/promu 40 | 41 | promu-build: gotest promu 42 | $(PROMU) build 43 | 44 | tarball: build promu 45 | @$(PROMU) tarball $(BIN_DIR) 46 | 47 | clean: 48 | @echo ">> cleaning up" 49 | @find . -type f -name '*~' -exec rm -fv {} \; 50 | @$(RM) $(TARGET) 51 | 52 | depcheck: $(GODEP) 53 | @echo ">> ensure vendoring" 54 | @$(GODEP) ensure 55 | 56 | gometalinter: $(GOLINTER) 57 | @echo ">> linting code" 58 | @$(GOLINTER) --install > /dev/null 59 | @$(GOLINTER) --config=./.gometalinter.json ./... 60 | 61 | $(GOPATH)/bin/dep dep: 62 | @GOOS=$(shell uname -s | tr A-Z a-z) \ 63 | GOARCH=$(subst x86_64,amd64,$(patsubst i%86,386,$(shell uname -m))) \ 64 | $(GO) get -u github.com/golang/dep/cmd/dep 65 | 66 | $(GOPATH)/bin/gometalinter lint: 67 | @GOOS=$(shell uname -s | tr A-Z a-z) \ 68 | GOARCH=$(subst x86_64,amd64,$(patsubst i%86,386,$(shell uname -m))) \ 69 | $(GO) get -u github.com/alecthomas/gometalinter 70 | 71 | .PHONY: all format vet build gotest promu promu-build clean $(GOPATH)/bin/promu $(GOPATH)/bin/dep dep depcheck $(GOPATH)/bin/gometalinter lint 72 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | THIS SOFTWARE IS PRE ALPHA SO BE CAREFUL 2 | 3 | Gluster Exporter -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/ofesseler/gluster_exporter.svg?branch=dev)](https://travis-ci.org/ofesseler/gluster_exporter) 2 | [![CircleCI](https://circleci.com/gh/ofesseler/gluster_exporter/tree/dev.svg?style=svg)](https://circleci.com/gh/ofesseler/gluster_exporter/tree/dev) 3 | # gluster_exporter 4 | Gluster exporter for Prometheus 5 | 6 | 7 | ## Installation 8 | 9 | ``` 10 | go get github.com/ofesseler/gluster_exporter 11 | ./gluster_exporter 12 | ``` 13 | 14 | ## Usage of `gluster_exporter` 15 | 16 | | Option | Default | Description 17 | | ------------------------- | ------------------- | ----------------- 18 | | -h, --help | - | Displays usage. 19 | | --web.listen-address | `:9189` | The address to listen on for HTTP requests. 20 | | --web.metrics-path | `/metrics` | URL Endpoint for metrics 21 | | --gluster.volumes | `_all` | Comma separated volume names: vol1,vol2,vol3. Default is '_all' to scrape all metrics 22 | | --gluster.executable-path | `/usr/sbin/gluster` | Path to gluster executable. 23 | | --profile | `false` | Enable gluster profiling reports. 24 | | --quota | `false` | Enable gluster quota reports. 25 | | --log.format | `logger:stderr` | Set the log target and format. Example: "logger:syslog?appname=bob&local=7" or "logger:stdout?json=true" 26 | | --log.level | `info` | Only log messages with the given severity or above. Valid levels: [debug, info, warn, error, fatal] 27 | | --version | - | Prints version information 28 | 29 | ## Make 30 | ``` 31 | build: Go build 32 | docker: build and run in docker container 33 | gometalinter: run some linting checks 34 | gotest: run go tests and reformats 35 | 36 | ``` 37 | 38 | **build**: runs go build for gluster_exporter 39 | 40 | **docker**: runs docker build and copy new built gluster_exporter 41 | 42 | **gometalinter**: runs [gometalinter](https://github.com/alecthomas/gometalinter) lint tools 43 | 44 | **gotest**: runs *vet* and *fmt* go tools 45 | 46 | ## Relevant Gluster Metrics 47 | Commands within the exporter are executed with `--xml`. 48 | 49 | ### Command: `gluster volume info` 50 | 51 | | Name | type | impl. state | 52 | | ------------ | -------- | ------------| 53 | | OpErrno | Gauge | implemented | 54 | | opRet | Gauge | implemented | 55 | | Status | Gauge | implemented | 56 | | BrickCount | Gauge | implemented | 57 | | Volumes.Count | Gauge | implemented | 58 | | Volume.Status | Gauge | implemented | 59 | 60 | 61 | ### Command: `gluster peer status` 62 | 63 | | Name | type | impl. state | 64 | | ------------------------- | -------- | ------------| 65 | | peerStatus.peer.state | Gauge | pending | 66 | | peerStatus.peer.connected | Gauge | implemented | 67 | 68 | 69 | ### Command: `gluster volume profile gv_test info cumulative` 70 | 71 | | Name | type | impl. state | 72 | | -------------------------------------------------- | -------- | ------------| 73 | | VolProfile.ProfileOp | Gauge | pending | 74 | | VolProfile.BrickCount | Gauge | implemented | 75 | | VolProfile.CumulativeStatus.Duration | Count | implemented | 76 | | VolProfile.CumulativeStatus.TotalRead | Count | implemented | 77 | | VolProfile.CumulativeStatus.TotalWrite | Count | implemented | 78 | | VolProfile.CumulativeStats.FopStats.Fop.Name | CREATE, ENTRYLK, FINODELK, FLUSH, FXATTROP, LOOKUP, OPENDIR, READDIR, STATFS, WRITE | implemented as label | 79 | | VolProfile.CumulativeStats.FopStats.Fop.Hits | Count | implemented | 80 | | VolProfile.CumulativeStats.FopStats.Fop.AvgLatency | Gauge | implemented | 81 | | VolProfile.CumulativeStats.FopStats.Fop.MinLatency | Gauge | implemented | 82 | | VolProfile.CumulativeStats.FopStats.Fop.MaxLatency | Gauge | implemented | 83 | 84 | 85 | ### Command `gluster volume status all detail` 86 | | Name | type | Labels | impl. state | 87 | |------|------|--------|-------------| 88 | | VolStatus.Volumes.Volume[].Node[].SizeFree | Gauge | hostname, path, volume | implemented | 89 | | VolStatus.Volumes.Volume[].Node[].SizeTotal | Count | hostname, path, volume | implemented | 90 | | VolStatus.Volumes.Volume[].Node[].InodesFree | Gauge | hostname, path, volume | implemented | 91 | | VolStatus.Volumes.Volume[].Node[].InodesTotal | Count | hostname, path, volume | implemented | 92 | 93 | 94 | ### Metrics in prometheus 95 | | Name | Description | 96 | | ------------ | -------- | 97 | | up | Was the last query of Gluster successful. | 98 | | volumes_available | How many volumes were up at the last query. | 99 | | volume_status | Status code of requested volume. | 100 | | node_size_free_bytes | Free bytes reported for each node on each instance. Labels are to distinguish origins. | 101 | | node_size_bytes_total | Total bytes reported for each node on each instance. Labels are to distinguish origins. | 102 | | node_inodes_free | Free inodes reported for each node on each instance. Labels are to distinguish origins. | 103 | | node_inodes_total | Total inodes reported for each node on each instance. Labels are to distinguish origins. | 104 | | brick_available | Number of bricks available at last query. | 105 | | brick_duration_seconds_total | Time running volume brick in seconds. | 106 | | brick_data_read_bytes_total | Total amount of bytes of data read by brick. | 107 | | brick_data_written_bytes_total| Total amount of bytes of data written by brick. | 108 | | brick_fop_hits_total | Total amount of file operation hits. | 109 | | brick_fop_latency_avg | Average fileoperations latency over total uptime | 110 | | brick_fop_latency_min | Minimum fileoperations latency over total uptime | 111 | | brick_fop_latency_max | Maximum fileoperations latency over total uptime | 112 | | peers_connected | Is peer connected to gluster cluster. | 113 | | heal_info_files_count | File count of files out of sync, when calling 'gluster v heal VOLNAME info | 114 | | volume_writeable | Writes and deletes file in Volume and checks if it is writeable | 115 | | mount_successful | Checks if mountpoint exists, returns a bool value 0 or 1 | 116 | 117 | 118 | ## Troubleshooting 119 | If the following message appears while trying to get some information out of your gluster. Increase scrape interval in `prometheus.yml` to at least 30s. 120 | 121 | ``` 122 | Another transaction is in progress for gv_cluster. Please try again after sometime 123 | ``` 124 | 125 | ## Contributors 126 | - coder-hugo 127 | - mjtrangoni 128 | 129 | ## Similar Projects 130 | glusterfs exporter for prometheus written in rust. 131 | - https://github.com/ibotty/glusterfs-exporter 132 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 0.2.8 2 | -------------------------------------------------------------------------------- /gluster-init.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | #GlusterFS configuration variables 4 | VOLNAME="data" 5 | 6 | # Start gluster manually (systemd is not running) 7 | /usr/sbin/glusterd -p /var/run/glusterd.pid --log-level INFO & 8 | # Wait to start configuring gluster 9 | sleep 30 10 | # Create a volume 11 | gluster volume create "$VOLNAME" "$(hostname)":/"$VOLNAME" force 12 | # Start Gluster volume 13 | gluster volume start "$VOLNAME" 14 | # Enable gluster profile 15 | gluster volume profile "$VOLNAME" start 16 | 17 | # Mount the volume 18 | glusterfs --volfile-server=localhost --volfile-id="$VOLNAME" /mnt/"$VOLNAME" 19 | 20 | # Write something to the volume 21 | dd if=/dev/zero of=/mnt/"$VOLNAME"/test.zero bs=1M count=10 22 | dd if=/dev/urandom of=/mnt/"$VOLNAME"/test.random bs=1M count=10 23 | 24 | # Show the exporter version 25 | /usr/bin/gluster_exporter --version 26 | 27 | # Start gluster_exporter 28 | /usr/bin/gluster_exporter --gluster.volumes="data" --profile 29 | 30 | # Stop glusterfs 31 | kill -9 "$(cat /var/run/glusterd.pid)" 32 | 33 | exit 0 34 | -------------------------------------------------------------------------------- /gluster_client.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "os" 7 | "os/exec" 8 | "strconv" 9 | "time" 10 | 11 | "github.com/ofesseler/gluster_exporter/structs" 12 | "github.com/prometheus/common/log" 13 | ) 14 | 15 | func execGlusterCommand(arg ...string) (*bytes.Buffer, error) { 16 | stdoutBuffer := &bytes.Buffer{} 17 | argXML := append(arg, "--xml") 18 | glusterExec := exec.Command(GlusterCmd, argXML...) 19 | glusterExec.Stdout = stdoutBuffer 20 | err := glusterExec.Run() 21 | 22 | if err != nil { 23 | log.Errorf("tried to execute %v and got error: %v", arg, err) 24 | return stdoutBuffer, err 25 | } 26 | return stdoutBuffer, nil 27 | } 28 | 29 | func execMountCheck() (*bytes.Buffer, error) { 30 | stdoutBuffer := &bytes.Buffer{} 31 | mountCmd := exec.Command("mount", "-t", "fuse.glusterfs") 32 | 33 | mountCmd.Stdout = stdoutBuffer 34 | 35 | return stdoutBuffer, mountCmd.Run() 36 | } 37 | 38 | func execTouchOnVolumes(mountpoint string) (bool, error) { 39 | testFileName := fmt.Sprintf("%v/%v_%v", mountpoint, "gluster_mount.test", time.Now()) 40 | _, createErr := os.Create(testFileName) 41 | if createErr != nil { 42 | return false, createErr 43 | } 44 | removeErr := os.Remove(testFileName) 45 | if removeErr != nil { 46 | return false, removeErr 47 | } 48 | return true, nil 49 | } 50 | 51 | // ExecVolumeInfo executes "gluster volume info" at the local machine and 52 | // returns VolumeInfoXML struct and error 53 | func ExecVolumeInfo() (structs.VolumeInfoXML, error) { 54 | args := []string{"volume", "info"} 55 | bytesBuffer, cmdErr := execGlusterCommand(args...) 56 | if cmdErr != nil { 57 | return structs.VolumeInfoXML{}, cmdErr 58 | } 59 | volumeInfo, err := structs.VolumeInfoXMLUnmarshall(bytesBuffer) 60 | if err != nil { 61 | log.Errorf("Something went wrong while unmarshalling xml: %v", err) 62 | return volumeInfo, err 63 | } 64 | 65 | return volumeInfo, nil 66 | } 67 | 68 | // ExecVolumeList executes "gluster volume info" at the local machine and 69 | // returns VolumeList struct and error 70 | func ExecVolumeList() (structs.VolList, error) { 71 | args := []string{"volume", "list"} 72 | bytesBuffer, cmdErr := execGlusterCommand(args...) 73 | if cmdErr != nil { 74 | return structs.VolList{}, cmdErr 75 | } 76 | volumeList, err := structs.VolumeListXMLUnmarshall(bytesBuffer) 77 | if err != nil { 78 | log.Errorf("Something went wrong while unmarshalling xml: %v", err) 79 | return volumeList.VolList, err 80 | } 81 | 82 | return volumeList.VolList, nil 83 | } 84 | 85 | // ExecPeerStatus executes "gluster peer status" at the local machine and 86 | // returns PeerStatus struct and error 87 | func ExecPeerStatus() (structs.PeerStatus, error) { 88 | args := []string{"peer", "status"} 89 | bytesBuffer, cmdErr := execGlusterCommand(args...) 90 | if cmdErr != nil { 91 | return structs.PeerStatus{}, cmdErr 92 | } 93 | peerStatus, err := structs.PeerStatusXMLUnmarshall(bytesBuffer) 94 | if err != nil { 95 | log.Errorf("Something went wrong while unmarshalling xml: %v", err) 96 | return peerStatus.PeerStatus, err 97 | } 98 | 99 | return peerStatus.PeerStatus, nil 100 | } 101 | 102 | // ExecVolumeProfileGvInfoCumulative executes "gluster volume {volume] profile info cumulative" at the local machine and 103 | // returns VolumeInfoXML struct and error 104 | func ExecVolumeProfileGvInfoCumulative(volumeName string) (structs.VolProfile, error) { 105 | args := []string{"volume", "profile", volumeName, "info", "cumulative"} 106 | bytesBuffer, cmdErr := execGlusterCommand(args...) 107 | if cmdErr != nil { 108 | return structs.VolProfile{}, cmdErr 109 | } 110 | volumeProfile, err := structs.VolumeProfileGvInfoCumulativeXMLUnmarshall(bytesBuffer) 111 | if err != nil { 112 | log.Errorf("Something went wrong while unmarshalling xml: %v", err) 113 | return volumeProfile.VolProfile, err 114 | } 115 | return volumeProfile.VolProfile, nil 116 | } 117 | 118 | // ExecVolumeStatusAllDetail executes "gluster volume status all detail" at the local machine 119 | // returns VolumeStatusXML struct and error 120 | func ExecVolumeStatusAllDetail() (structs.VolumeStatusXML, error) { 121 | args := []string{"volume", "status", "all", "detail"} 122 | bytesBuffer, cmdErr := execGlusterCommand(args...) 123 | if cmdErr != nil { 124 | return structs.VolumeStatusXML{}, cmdErr 125 | } 126 | volumeStatus, err := structs.VolumeStatusAllDetailXMLUnmarshall(bytesBuffer) 127 | if err != nil { 128 | log.Errorf("Something went wrong while unmarshalling xml: %v", err) 129 | return volumeStatus, err 130 | } 131 | return volumeStatus, nil 132 | } 133 | 134 | // ExecVolumeHealInfo executes volume heal info on host system and processes input 135 | // returns (int) number of unsynced files 136 | func ExecVolumeHealInfo(volumeName string) (int, error) { 137 | args := []string{"volume", "heal", volumeName, "info"} 138 | entriesOutOfSync := 0 139 | bytesBuffer, cmdErr := execGlusterCommand(args...) 140 | if cmdErr != nil { 141 | return -1, cmdErr 142 | } 143 | healInfo, err := structs.VolumeHealInfoXMLUnmarshall(bytesBuffer) 144 | if err != nil { 145 | log.Error(err) 146 | return -1, err 147 | } 148 | 149 | for _, brick := range healInfo.HealInfo.Bricks.Brick { 150 | var count int 151 | var err error 152 | count, err = strconv.Atoi(brick.NumberOfEntries) 153 | if err != nil { 154 | log.Error(err) 155 | return -1, err 156 | } 157 | entriesOutOfSync += count 158 | } 159 | return entriesOutOfSync, nil 160 | } 161 | 162 | // ExecVolumeQuotaList executes volume quota list on host system and processes input 163 | // returns QuotaList structs and errors 164 | func ExecVolumeQuotaList(volumeName string) (structs.VolumeQuotaXML, error) { 165 | args := []string{"volume", "quota", volumeName, "list"} 166 | bytesBuffer, cmdErr := execGlusterCommand(args...) 167 | if cmdErr != nil { 168 | return structs.VolumeQuotaXML{}, cmdErr 169 | } 170 | volumeQuota, err := structs.VolumeQuotaListXMLUnmarshall(bytesBuffer) 171 | if err != nil { 172 | log.Errorf("Something went wrong while unmarshalling xml: %v", err) 173 | return volumeQuota, err 174 | } 175 | return volumeQuota, nil 176 | } 177 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Oliver Fesseler 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // 8 | // Unless required by applicable law or agreed to in writing, software 9 | // distributed under the License is distributed on an "AS IS" BASIS, 10 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | // Gluster exporter, exports metrics from gluster commandline tool. 15 | package main 16 | 17 | import ( 18 | "net/http" 19 | 20 | "fmt" 21 | "os" 22 | "strings" 23 | 24 | "github.com/prometheus/client_golang/prometheus" 25 | "github.com/prometheus/client_golang/prometheus/promhttp" 26 | "github.com/prometheus/common/log" 27 | "github.com/prometheus/common/version" 28 | "gopkg.in/alecthomas/kingpin.v2" 29 | ) 30 | 31 | const ( 32 | // GlusterCmd is the default path to gluster binary 33 | GlusterCmd = "/usr/sbin/gluster" 34 | namespace = "gluster" 35 | allVolumes = "_all" 36 | ) 37 | 38 | var ( 39 | up = prometheus.NewDesc( 40 | prometheus.BuildFQName(namespace, "", "up"), 41 | "Was the last query of Gluster successful.", 42 | nil, nil, 43 | ) 44 | 45 | volumesCount = prometheus.NewDesc( 46 | prometheus.BuildFQName(namespace, "", "volumes_available"), 47 | "How many volumes were up at the last query.", 48 | nil, nil, 49 | ) 50 | 51 | volumeStatus = prometheus.NewDesc( 52 | prometheus.BuildFQName(namespace, "", "volume_status"), 53 | "Status code of requested volume.", 54 | []string{"volume"}, nil, 55 | ) 56 | 57 | nodeSizeFreeBytes = prometheus.NewDesc( 58 | prometheus.BuildFQName(namespace, "", "node_size_free_bytes"), 59 | "Free bytes reported for each node on each instance. Labels are to distinguish origins", 60 | []string{"hostname", "path", "volume"}, nil, 61 | ) 62 | 63 | nodeSizeTotalBytes = prometheus.NewDesc( 64 | prometheus.BuildFQName(namespace, "", "node_size_bytes_total"), 65 | "Total bytes reported for each node on each instance. Labels are to distinguish origins", 66 | []string{"hostname", "path", "volume"}, nil, 67 | ) 68 | 69 | nodeInodesTotal = prometheus.NewDesc( 70 | prometheus.BuildFQName(namespace, "", "node_inodes_total"), 71 | "Total inodes reported for each node on each instance. Labels are to distinguish origins", 72 | []string{"hostname", "path", "volume"}, nil, 73 | ) 74 | 75 | nodeInodesFree = prometheus.NewDesc( 76 | prometheus.BuildFQName(namespace, "", "node_inodes_free"), 77 | "Free inodes reported for each node on each instance. Labels are to distinguish origins", 78 | []string{"hostname", "path", "volume"}, nil, 79 | ) 80 | 81 | brickCount = prometheus.NewDesc( 82 | prometheus.BuildFQName(namespace, "", "brick_available"), 83 | "Number of bricks available at last query.", 84 | []string{"volume"}, nil, 85 | ) 86 | 87 | brickDuration = prometheus.NewDesc( 88 | prometheus.BuildFQName(namespace, "", "brick_duration_seconds_total"), 89 | "Time running volume brick in seconds.", 90 | []string{"volume", "brick"}, nil, 91 | ) 92 | 93 | brickDataRead = prometheus.NewDesc( 94 | prometheus.BuildFQName(namespace, "", "brick_data_read_bytes_total"), 95 | "Total amount of bytes of data read by brick.", 96 | []string{"volume", "brick"}, nil, 97 | ) 98 | 99 | brickDataWritten = prometheus.NewDesc( 100 | prometheus.BuildFQName(namespace, "", "brick_data_written_bytes_total"), 101 | "Total amount of bytes of data written by brick.", 102 | []string{"volume", "brick"}, nil, 103 | ) 104 | 105 | brickFopHits = prometheus.NewDesc( 106 | prometheus.BuildFQName(namespace, "", "brick_fop_hits_total"), 107 | "Total amount of file operation hits.", 108 | []string{"volume", "brick", "fop_name"}, nil, 109 | ) 110 | 111 | brickFopLatencyAvg = prometheus.NewDesc( 112 | prometheus.BuildFQName(namespace, "", "brick_fop_latency_avg"), 113 | "Average fileoperations latency over total uptime", 114 | []string{"volume", "brick", "fop_name"}, nil, 115 | ) 116 | 117 | brickFopLatencyMin = prometheus.NewDesc( 118 | prometheus.BuildFQName(namespace, "", "brick_fop_latency_min"), 119 | "Minimum fileoperations latency over total uptime", 120 | []string{"volume", "brick", "fop_name"}, nil, 121 | ) 122 | 123 | brickFopLatencyMax = prometheus.NewDesc( 124 | prometheus.BuildFQName(namespace, "", "brick_fop_latency_max"), 125 | "Maximum fileoperations latency over total uptime", 126 | []string{"volume", "brick", "fop_name"}, nil, 127 | ) 128 | 129 | peersConnected = prometheus.NewDesc( 130 | prometheus.BuildFQName(namespace, "", "peers_connected"), 131 | "Is peer connected to gluster cluster.", 132 | nil, nil, 133 | ) 134 | 135 | healInfoFilesCount = prometheus.NewDesc( 136 | prometheus.BuildFQName(namespace, "", "heal_info_files_count"), 137 | "File count of files out of sync, when calling 'gluster v heal VOLNAME info", 138 | []string{"volume"}, nil) 139 | 140 | volumeWriteable = prometheus.NewDesc( 141 | prometheus.BuildFQName(namespace, "", "volume_writeable"), 142 | "Writes and deletes file in Volume and checks if it is writeable", 143 | []string{"volume", "mountpoint"}, nil) 144 | 145 | mountSuccessful = prometheus.NewDesc( 146 | prometheus.BuildFQName(namespace, "", "mount_successful"), 147 | "Checks if mountpoint exists, returns a bool value 0 or 1", 148 | []string{"volume", "mountpoint"}, nil) 149 | 150 | quotaHardLimit = prometheus.NewDesc( 151 | prometheus.BuildFQName(namespace, "", "volume_quota_hardlimit"), 152 | "Quota hard limit (bytes) in a volume", 153 | []string{"path", "volume"}, nil) 154 | 155 | quotaSoftLimit = prometheus.NewDesc( 156 | prometheus.BuildFQName(namespace, "", "volume_quota_softlimit"), 157 | "Quota soft limit (bytes) in a volume", 158 | []string{"path", "volume"}, nil) 159 | 160 | quotaUsed = prometheus.NewDesc( 161 | prometheus.BuildFQName(namespace, "", "volume_quota_used"), 162 | "Current data (bytes) used in a quota", 163 | []string{"path", "volume"}, nil) 164 | 165 | quotaAvailable = prometheus.NewDesc( 166 | prometheus.BuildFQName(namespace, "", "volume_quota_available"), 167 | "Current data (bytes) available in a quota", 168 | []string{"path", "volume"}, nil) 169 | 170 | quotaSoftLimitExceeded = prometheus.NewDesc( 171 | prometheus.BuildFQName(namespace, "", "volume_quota_softlimit_exceeded"), 172 | "Is the quota soft-limit exceeded", 173 | []string{"path", "volume"}, nil) 174 | 175 | quotaHardLimitExceeded = prometheus.NewDesc( 176 | prometheus.BuildFQName(namespace, "", "volume_quota_hardlimit_exceeded"), 177 | "Is the quota hard-limit exceeded", 178 | []string{"path", "volume"}, nil) 179 | ) 180 | 181 | // Exporter holds name, path and volumes to be monitored 182 | type Exporter struct { 183 | hostname string 184 | path string 185 | volumes []string 186 | profile bool 187 | quota bool 188 | } 189 | 190 | // Describe all the metrics exported by Gluster exporter. It implements prometheus.Collector. 191 | func (e *Exporter) Describe(ch chan<- *prometheus.Desc) { 192 | ch <- up 193 | ch <- volumeStatus 194 | ch <- volumesCount 195 | ch <- brickCount 196 | ch <- brickDuration 197 | ch <- brickDataRead 198 | ch <- brickDataWritten 199 | ch <- peersConnected 200 | ch <- nodeSizeFreeBytes 201 | ch <- nodeSizeTotalBytes 202 | ch <- brickFopHits 203 | ch <- brickFopLatencyAvg 204 | ch <- brickFopLatencyMin 205 | ch <- brickFopLatencyMax 206 | ch <- healInfoFilesCount 207 | ch <- volumeWriteable 208 | ch <- mountSuccessful 209 | ch <- quotaHardLimit 210 | ch <- quotaSoftLimit 211 | ch <- quotaUsed 212 | ch <- quotaAvailable 213 | ch <- quotaSoftLimitExceeded 214 | ch <- quotaHardLimitExceeded 215 | } 216 | 217 | // Collect collects all the metrics 218 | func (e *Exporter) Collect(ch chan<- prometheus.Metric) { 219 | // Collect metrics from volume info 220 | volumeInfo, err := ExecVolumeInfo() 221 | // Couldn't parse xml, so something is really wrong and up=0 222 | if err != nil { 223 | log.Errorf("couldn't parse xml volume info: %v", err) 224 | ch <- prometheus.MustNewConstMetric( 225 | up, prometheus.GaugeValue, 0.0, 226 | ) 227 | } 228 | 229 | // use OpErrno as indicator for up 230 | if volumeInfo.OpErrno != 0 { 231 | ch <- prometheus.MustNewConstMetric( 232 | up, prometheus.GaugeValue, 0.0, 233 | ) 234 | } else { 235 | ch <- prometheus.MustNewConstMetric( 236 | up, prometheus.GaugeValue, 1.0, 237 | ) 238 | } 239 | 240 | ch <- prometheus.MustNewConstMetric( 241 | volumesCount, prometheus.GaugeValue, float64(volumeInfo.VolInfo.Volumes.Count), 242 | ) 243 | 244 | for _, volume := range volumeInfo.VolInfo.Volumes.Volume { 245 | if e.volumes[0] == allVolumes || ContainsVolume(e.volumes, volume.Name) { 246 | 247 | ch <- prometheus.MustNewConstMetric( 248 | brickCount, prometheus.GaugeValue, float64(volume.BrickCount), volume.Name, 249 | ) 250 | 251 | ch <- prometheus.MustNewConstMetric( 252 | volumeStatus, prometheus.GaugeValue, float64(volume.Status), volume.Name, 253 | ) 254 | } 255 | } 256 | 257 | // reads gluster peer status 258 | peerStatus, peerStatusErr := ExecPeerStatus() 259 | if peerStatusErr != nil { 260 | log.Errorf("couldn't parse xml of peer status: %v", peerStatusErr) 261 | } 262 | count := 0 263 | for range peerStatus.Peer { 264 | count++ 265 | } 266 | ch <- prometheus.MustNewConstMetric( 267 | peersConnected, prometheus.GaugeValue, float64(count), 268 | ) 269 | 270 | // reads profile info 271 | if e.profile { 272 | for _, volume := range volumeInfo.VolInfo.Volumes.Volume { 273 | if e.volumes[0] == allVolumes || ContainsVolume(e.volumes, volume.Name) { 274 | volumeProfile, execVolProfileErr := ExecVolumeProfileGvInfoCumulative(volume.Name) 275 | if execVolProfileErr != nil { 276 | log.Errorf("Error while executing or marshalling gluster profile output: %v", execVolProfileErr) 277 | } 278 | for _, brick := range volumeProfile.Brick { 279 | if strings.HasPrefix(brick.BrickName, e.hostname) { 280 | ch <- prometheus.MustNewConstMetric( 281 | brickDuration, prometheus.CounterValue, float64(brick.CumulativeStats.Duration), volume.Name, brick.BrickName, 282 | ) 283 | 284 | ch <- prometheus.MustNewConstMetric( 285 | brickDataRead, prometheus.CounterValue, float64(brick.CumulativeStats.TotalRead), volume.Name, brick.BrickName, 286 | ) 287 | 288 | ch <- prometheus.MustNewConstMetric( 289 | brickDataWritten, prometheus.CounterValue, float64(brick.CumulativeStats.TotalWrite), volume.Name, brick.BrickName, 290 | ) 291 | for _, fop := range brick.CumulativeStats.FopStats.Fop { 292 | ch <- prometheus.MustNewConstMetric( 293 | brickFopHits, prometheus.CounterValue, float64(fop.Hits), volume.Name, brick.BrickName, fop.Name, 294 | ) 295 | 296 | ch <- prometheus.MustNewConstMetric( 297 | brickFopLatencyAvg, prometheus.GaugeValue, fop.AvgLatency, volume.Name, brick.BrickName, fop.Name, 298 | ) 299 | 300 | ch <- prometheus.MustNewConstMetric( 301 | brickFopLatencyMin, prometheus.GaugeValue, fop.MinLatency, volume.Name, brick.BrickName, fop.Name, 302 | ) 303 | 304 | ch <- prometheus.MustNewConstMetric( 305 | brickFopLatencyMax, prometheus.GaugeValue, fop.MaxLatency, volume.Name, brick.BrickName, fop.Name, 306 | ) 307 | } 308 | } 309 | } 310 | } 311 | } 312 | } 313 | 314 | // executes gluster status all detail 315 | volumeStatusAll, err := ExecVolumeStatusAllDetail() 316 | if err != nil { 317 | log.Errorf("couldn't parse xml of peer status: %v", err) 318 | } 319 | for _, vol := range volumeStatusAll.VolStatus.Volumes.Volume { 320 | for _, node := range vol.Node { 321 | ch <- prometheus.MustNewConstMetric( 322 | nodeSizeTotalBytes, prometheus.CounterValue, float64(node.SizeTotal), node.Hostname, node.Path, vol.VolName, 323 | ) 324 | 325 | ch <- prometheus.MustNewConstMetric( 326 | nodeSizeFreeBytes, prometheus.GaugeValue, float64(node.SizeFree), node.Hostname, node.Path, vol.VolName, 327 | ) 328 | ch <- prometheus.MustNewConstMetric( 329 | nodeInodesTotal, prometheus.CounterValue, float64(node.InodesTotal), node.Hostname, node.Path, vol.VolName, 330 | ) 331 | 332 | ch <- prometheus.MustNewConstMetric( 333 | nodeInodesFree, prometheus.GaugeValue, float64(node.InodesFree), node.Hostname, node.Path, vol.VolName, 334 | ) 335 | } 336 | } 337 | vols := e.volumes 338 | if vols[0] == allVolumes { 339 | log.Warn("no Volumes were given.") 340 | volumeList, volumeListErr := ExecVolumeList() 341 | if volumeListErr != nil { 342 | log.Error(volumeListErr) 343 | } 344 | vols = volumeList.Volume 345 | } 346 | 347 | for _, vol := range vols { 348 | filesCount, volumeHealErr := ExecVolumeHealInfo(vol) 349 | if volumeHealErr == nil { 350 | ch <- prometheus.MustNewConstMetric( 351 | healInfoFilesCount, prometheus.CounterValue, float64(filesCount), vol, 352 | ) 353 | } 354 | } 355 | 356 | mountBuffer, execMountCheckErr := execMountCheck() 357 | if execMountCheckErr != nil { 358 | log.Error(execMountCheckErr) 359 | } else { 360 | mounts, err := parseMountOutput(mountBuffer.String()) 361 | if err != nil { 362 | log.Error(err) 363 | if len(mounts) > 0 { 364 | for _, mount := range mounts { 365 | ch <- prometheus.MustNewConstMetric( 366 | mountSuccessful, prometheus.GaugeValue, float64(0), mount.volume, mount.mountPoint, 367 | ) 368 | } 369 | } 370 | } else { 371 | for _, mount := range mounts { 372 | ch <- prometheus.MustNewConstMetric( 373 | mountSuccessful, prometheus.GaugeValue, float64(1), mount.volume, mount.mountPoint, 374 | ) 375 | 376 | isWriteable, err := execTouchOnVolumes(mount.mountPoint) 377 | if err != nil { 378 | log.Error(err) 379 | } 380 | if isWriteable { 381 | ch <- prometheus.MustNewConstMetric( 382 | volumeWriteable, prometheus.GaugeValue, float64(1), mount.volume, mount.mountPoint, 383 | ) 384 | } else { 385 | ch <- prometheus.MustNewConstMetric( 386 | volumeWriteable, prometheus.GaugeValue, float64(0), mount.volume, mount.mountPoint, 387 | ) 388 | } 389 | } 390 | } 391 | } 392 | if e.quota { 393 | for _, volume := range volumeInfo.VolInfo.Volumes.Volume { 394 | if e.volumes[0] == allVolumes || ContainsVolume(e.volumes, volume.Name) { 395 | volumeQuotaXML, err := ExecVolumeQuotaList(volume.Name) 396 | if err != nil { 397 | log.Error("Cannot create quota metrics if quotas are not enabled in your gluster server") 398 | } else { 399 | for _, limit := range volumeQuotaXML.VolQuota.QuotaLimits { 400 | ch <- prometheus.MustNewConstMetric( 401 | quotaHardLimit, 402 | prometheus.CounterValue, 403 | float64(limit.HardLimit), 404 | limit.Path, 405 | volume.Name, 406 | ) 407 | 408 | ch <- prometheus.MustNewConstMetric( 409 | quotaSoftLimit, 410 | prometheus.CounterValue, 411 | float64(limit.SoftLimitValue), 412 | limit.Path, 413 | volume.Name, 414 | ) 415 | ch <- prometheus.MustNewConstMetric( 416 | quotaUsed, 417 | prometheus.CounterValue, 418 | float64(limit.UsedSpace), 419 | limit.Path, 420 | volume.Name, 421 | ) 422 | 423 | ch <- prometheus.MustNewConstMetric( 424 | quotaAvailable, 425 | prometheus.CounterValue, 426 | float64(limit.AvailSpace), 427 | limit.Path, 428 | volume.Name, 429 | ) 430 | 431 | slExceeded := 0.0 432 | if limit.SlExceeded != "No" { 433 | slExceeded = 1.0 434 | } 435 | ch <- prometheus.MustNewConstMetric( 436 | quotaSoftLimitExceeded, 437 | prometheus.CounterValue, 438 | slExceeded, 439 | limit.Path, 440 | volume.Name, 441 | ) 442 | 443 | hlExceeded := 0.0 444 | if limit.HlExceeded != "No" { 445 | hlExceeded = 1.0 446 | } 447 | ch <- prometheus.MustNewConstMetric( 448 | quotaHardLimitExceeded, 449 | prometheus.CounterValue, 450 | hlExceeded, 451 | limit.Path, 452 | volume.Name, 453 | ) 454 | } 455 | } 456 | } 457 | } 458 | } 459 | } 460 | 461 | type mount struct { 462 | mountPoint string 463 | volume string 464 | } 465 | 466 | // ParseMountOutput pares output of system execution 'mount' 467 | func parseMountOutput(mountBuffer string) ([]mount, error) { 468 | mounts := make([]mount, 0, 2) 469 | mountRows := strings.Split(mountBuffer, "\n") 470 | for _, row := range mountRows { 471 | trimmedRow := strings.TrimSpace(row) 472 | if len(row) > 3 { 473 | mountColumns := strings.Split(trimmedRow, " ") 474 | mounts = append(mounts, mount{mountPoint: mountColumns[2], volume: mountColumns[0]}) 475 | } 476 | } 477 | return mounts, nil 478 | } 479 | 480 | // ContainsVolume checks a slice if it contains an element 481 | func ContainsVolume(slice []string, element string) bool { 482 | for _, a := range slice { 483 | if a == element { 484 | return true 485 | } 486 | } 487 | return false 488 | } 489 | 490 | // NewExporter initialises exporter 491 | func NewExporter(hostname, glusterExecPath, volumesString string, profile bool, quota bool) (*Exporter, error) { 492 | if len(glusterExecPath) < 1 { 493 | log.Fatalf("Gluster executable path is wrong: %v", glusterExecPath) 494 | } 495 | volumes := strings.Split(volumesString, ",") 496 | if len(volumes) < 1 { 497 | log.Warnf("No volumes given. Proceeding without volume information. Volumes: %v", volumesString) 498 | } 499 | 500 | return &Exporter{ 501 | hostname: hostname, 502 | path: glusterExecPath, 503 | volumes: volumes, 504 | profile: profile, 505 | quota: quota, 506 | }, nil 507 | } 508 | 509 | func init() { 510 | prometheus.MustRegister(version.NewCollector("gluster_exporter")) 511 | } 512 | 513 | func main() { 514 | 515 | // commandline arguments 516 | var ( 517 | metricsPath = kingpin.Flag("web.telemetry-path", "Path under which to expose metrics.").Default("/metrics").String() 518 | listenAddress = kingpin.Flag("web.listen-address", "Address on which to expose metrics and web interface.").Default(":9189").String() 519 | glusterPath = kingpin.Flag("gluster.executable-path", "Path to gluster executable.").Default(GlusterCmd).String() 520 | glusterVolumes = kingpin.Flag("gluster.volumes", fmt.Sprintf("Comma separated volume names: vol1,vol2,vol3. Default is '%v' to scrape all metrics", allVolumes)).Default(allVolumes).String() 521 | profile = kingpin.Flag("profile", "Enable gluster profiling reports.").Bool() 522 | quota = kingpin.Flag("quota", "Enable gluster quota reports.").Bool() 523 | num int 524 | ) 525 | 526 | log.AddFlags(kingpin.CommandLine) 527 | kingpin.Version(version.Print("gluster_exporter")) 528 | kingpin.HelpFlag.Short('h') 529 | kingpin.Parse() 530 | 531 | log.Infoln("Starting gluster_exporter", version.Info()) 532 | log.Infoln("Build context", version.BuildContext()) 533 | 534 | hostname, err := os.Hostname() 535 | if err != nil { 536 | log.Fatalf("While trying to get Hostname error happened: %v", err) 537 | } 538 | exporter, err := NewExporter(hostname, *glusterPath, *glusterVolumes, *profile, *quota) 539 | if err != nil { 540 | log.Errorf("Creating new Exporter went wrong, ... \n%v", err) 541 | } 542 | prometheus.MustRegister(exporter) 543 | 544 | http.Handle("/metrics", promhttp.Handler()) 545 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 546 | num, err = w.Write([]byte(` 547 | GlusterFS Exporter v` + version.Version + ` 548 | 549 |

GlusterFS Exporter v` + version.Version + `

550 |

Metrics

551 | 552 | `)) 553 | if err != nil { 554 | log.Fatal(num, err) 555 | } 556 | }) 557 | 558 | log.Infoln("Listening on", *listenAddress) 559 | err = http.ListenAndServe(*listenAddress, nil) 560 | if err != nil { 561 | log.Fatal(err) 562 | } 563 | } 564 | -------------------------------------------------------------------------------- /main_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "testing" 4 | 5 | func TestContainsVolume(t *testing.T) { 6 | expamle := "doge" 7 | testSlice := []string{"wow", "such", expamle} 8 | if !ContainsVolume(testSlice, expamle) { 9 | t.Fatalf("Hasn't found %v in slice %v", expamle, testSlice) 10 | } 11 | } 12 | 13 | type testCases struct { 14 | mountOutput string 15 | expected []string 16 | } 17 | 18 | func TestParseMountOutput(t *testing.T) { 19 | var tests = []testCases{ 20 | { 21 | mountOutput: "/dev/mapper/cryptroot on / type ext4 (rw,relatime,data=ordered) \n" + 22 | "/dev/mapper/cryptroot on /var/lib/docker/devicemapper type ext4 (rw,relatime,data=ordered)", 23 | expected: []string{"/", "/var/lib/docker/devicemapper"}, 24 | }, 25 | { 26 | mountOutput: "/dev/mapper/cryptroot on / type ext4 (rw,relatime,data=ordered) \n" + 27 | "", 28 | expected: []string{"/"}, 29 | }, 30 | } 31 | for _, c := range tests { 32 | mounts, err := parseMountOutput(c.mountOutput) 33 | if err != nil { 34 | t.Error(err) 35 | } 36 | 37 | for i, mount := range mounts { 38 | if mount.mountPoint != c.expected[i] { 39 | t.Errorf("mountpoint is %v and %v was expected", mount.mountPoint, c.expected[i]) 40 | } 41 | } 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /structs/xmlStructs.go: -------------------------------------------------------------------------------- 1 | package structs 2 | 3 | import ( 4 | "encoding/xml" 5 | "io" 6 | "io/ioutil" 7 | 8 | "github.com/prometheus/common/log" 9 | ) 10 | 11 | // VolumeInfoXML struct represents cliOutput element of "gluster volume info" command 12 | type VolumeInfoXML struct { 13 | XMLName xml.Name `xml:"cliOutput"` 14 | OpRet int `xml:"opRet"` 15 | OpErrno int `xml:"opErrno"` 16 | OpErrstr string `xml:"opErrstr"` 17 | VolInfo VolInfo `xml:"volInfo"` 18 | } 19 | 20 | // VolInfo element of "gluster volume info" command 21 | type VolInfo struct { 22 | XMLName xml.Name `xml:"volInfo"` 23 | Volumes Volumes `xml:"volumes"` 24 | } 25 | 26 | // Volumes element of "gluster volume info" command 27 | type Volumes struct { 28 | XMLName xml.Name `xml:"volumes"` 29 | Volume []Volume `xml:"volume"` 30 | Count int `xml:"count"` 31 | } 32 | 33 | // Volume element of "gluster volume info" command 34 | type Volume struct { 35 | XMLName xml.Name `xml:"volume"` 36 | Name string `xml:"name"` 37 | ID string `xml:"id"` 38 | Status int `xml:"status"` 39 | StatusStr string `xml:"statusStr"` 40 | BrickCount int `xml:"brickCount"` 41 | Bricks []Brick `xml:"bricks"` 42 | DistCount int `xml:"distCount"` 43 | } 44 | 45 | // Brick element of "gluster volume info" command 46 | type Brick struct { 47 | UUID string `xml:"brick>uuid"` 48 | Name string `xml:"brick>name"` 49 | HostUUID string `xml:"brick>hostUuid"` 50 | IsArbiter int `xml:"brick>isArbiter"` 51 | } 52 | 53 | // VolumeListXML struct represents cliOutput element of "gluster volume list" command 54 | type VolumeListXML struct { 55 | XMLName xml.Name `xml:"cliOutput"` 56 | OpRet int `xml:"opRet"` 57 | OpErrno int `xml:"opErrno"` 58 | OpErrstr string `xml:"opErrstr"` 59 | VolList VolList `xml:"volList"` 60 | } 61 | 62 | // VolList element of "gluster volume list" command 63 | type VolList struct { 64 | Count int `xml:"count"` 65 | Volume []string `xml:"volume"` 66 | } 67 | 68 | // PeerStatusXML struct represents cliOutput element of "gluster peer status" command 69 | type PeerStatusXML struct { 70 | XMLName xml.Name `xml:"cliOutput"` 71 | OpRet int `xml:"opRet"` 72 | OpErrno int `xml:"opErrno"` 73 | OpErrstr string `xml:"opErrstr"` 74 | PeerStatus PeerStatus `xml:"peerStatus"` 75 | } 76 | 77 | // PeerStatus element of "gluster peer status" command 78 | type PeerStatus struct { 79 | XMLName xml.Name `xml:"peerStatus"` 80 | Peer []Peer `xml:"peer"` 81 | } 82 | 83 | // Peer element of "gluster peer status" command 84 | type Peer struct { 85 | XMLName xml.Name `xml:"peer"` 86 | UUID string `xml:"uuid"` 87 | Hostname string `xml:"hostname"` 88 | Hostnames Hostnames `xml:"hostnames"` 89 | Connected int `xml:"connected"` 90 | State int `xml:"state"` 91 | StateStr string `xml:"stateStr"` 92 | } 93 | 94 | // Hostnames element of "gluster peer status" command 95 | type Hostnames struct { 96 | Hostname string `xml:"hostname"` 97 | } 98 | 99 | // VolumeProfileXML struct represents cliOutput element of "gluster volume {volume} profile" command 100 | type VolumeProfileXML struct { 101 | XMLName xml.Name `xml:"cliOutput"` 102 | OpRet int `xml:"opRet"` 103 | OpErrno int `xml:"opErrno"` 104 | OpErrstr string `xml:"opErrstr"` 105 | VolProfile VolProfile `xml:"volProfile"` 106 | } 107 | 108 | // VolProfile element of "gluster volume {volume} profile" command 109 | type VolProfile struct { 110 | Volname string `xml:"volname"` 111 | BrickCount int `xml:"brickCount"` 112 | Brick []BrickProfile `xml:"brick"` 113 | } 114 | 115 | // BrickProfile struct for element brick of "gluster volume {volume} profile" command 116 | type BrickProfile struct { 117 | //XMLName xml.Name `xml:"brick"` 118 | BrickName string `xml:"brickName"` 119 | CumulativeStats CumulativeStats `xml:"cumulativeStats"` 120 | } 121 | 122 | // CumulativeStats element of "gluster volume {volume} profile" command 123 | type CumulativeStats struct { 124 | FopStats FopStats `xml:"fopStats"` 125 | Duration int `xml:"duration"` 126 | TotalRead int `xml:"totalRead"` 127 | TotalWrite int `xml:"totalWrite"` 128 | } 129 | 130 | // FopStats element of "gluster volume {volume} profile" command 131 | type FopStats struct { 132 | Fop []Fop `xml:"fop"` 133 | } 134 | 135 | // Fop is struct for FopStats 136 | type Fop struct { 137 | Name string `xml:"name"` 138 | Hits int `xml:"hits"` 139 | AvgLatency float64 `xml:"avgLatency"` 140 | MinLatency float64 `xml:"minLatency"` 141 | MaxLatency float64 `xml:"maxLatency"` 142 | } 143 | 144 | // HealInfoBrick is a struct of HealInfoBricks 145 | type HealInfoBrick struct { 146 | XMLName xml.Name `xml:"brick"` 147 | Name string `xml:"name"` 148 | Status string `xml:"status"` 149 | NumberOfEntries string `xml:"numberOfEntries"` 150 | } 151 | 152 | // HealInfoBricks is a struct of HealInfo 153 | type HealInfoBricks struct { 154 | XMLName xml.Name `xml:"bricks"` 155 | Brick []HealInfoBrick `xml:"brick"` 156 | } 157 | 158 | // HealInfo is a struct of VolumenHealInfoXML 159 | type HealInfo struct { 160 | XMLName xml.Name `xml:"healInfo"` 161 | Bricks HealInfoBricks `xml:"bricks"` 162 | } 163 | 164 | // VolumeHealInfoXML struct represents cliOutput element of "gluster volume {volume} heal info" command 165 | type VolumeHealInfoXML struct { 166 | XMLName xml.Name `xml:"cliOutput"` 167 | OpRet int `xml:"opRet"` 168 | OpErrno int `xml:"opErrno"` 169 | OpErrstr string `xml:"opErrstr"` 170 | HealInfo HealInfo `xml:"healInfo"` 171 | } 172 | 173 | // VolumeHealInfoXMLUnmarshall unmarshalls heal info of gluster cluster 174 | func VolumeHealInfoXMLUnmarshall(cmdOutBuff io.Reader) (VolumeHealInfoXML, error) { 175 | var vol VolumeHealInfoXML 176 | b, err := ioutil.ReadAll(cmdOutBuff) 177 | if err != nil { 178 | log.Error(err) 179 | return vol, err 180 | } 181 | err = xml.Unmarshal(b, &vol) 182 | if err != nil { 183 | log.Error(err) 184 | } 185 | return vol, nil 186 | } 187 | 188 | // VolumeListXMLUnmarshall unmarshalls bytes to VolumeListXML struct 189 | func VolumeListXMLUnmarshall(cmdOutBuff io.Reader) (VolumeListXML, error) { 190 | var vol VolumeListXML 191 | b, err := ioutil.ReadAll(cmdOutBuff) 192 | if err != nil { 193 | log.Error(err) 194 | return vol, err 195 | } 196 | err = xml.Unmarshal(b, &vol) 197 | return vol, err 198 | } 199 | 200 | // VolumeInfoXMLUnmarshall unmarshalls bytes to VolumeInfoXML struct 201 | func VolumeInfoXMLUnmarshall(cmdOutBuff io.Reader) (VolumeInfoXML, error) { 202 | var vol VolumeInfoXML 203 | b, err := ioutil.ReadAll(cmdOutBuff) 204 | if err != nil { 205 | log.Error(err) 206 | return vol, err 207 | } 208 | err = xml.Unmarshal(b, &vol) 209 | return vol, err 210 | } 211 | 212 | // PeerStatusXMLUnmarshall unmarshalls bytes to PeerStatusXML struct 213 | func PeerStatusXMLUnmarshall(cmdOutBuff io.Reader) (PeerStatusXML, error) { 214 | var vol PeerStatusXML 215 | b, err := ioutil.ReadAll(cmdOutBuff) 216 | if err != nil { 217 | log.Error(err) 218 | return vol, err 219 | } 220 | err = xml.Unmarshal(b, &vol) 221 | return vol, err 222 | } 223 | 224 | // VolumeProfileGvInfoCumulativeXMLUnmarshall unmarshalls cumulative profile of gluster volume profile 225 | func VolumeProfileGvInfoCumulativeXMLUnmarshall(cmdOutBuff io.Reader) (VolumeProfileXML, error) { 226 | var vol VolumeProfileXML 227 | b, err := ioutil.ReadAll(cmdOutBuff) 228 | if err != nil { 229 | log.Error(err) 230 | return vol, err 231 | } 232 | err = xml.Unmarshal(b, &vol) 233 | return vol, err 234 | } 235 | 236 | // VolumeStatusXML XML type of "gluster volume status" 237 | type VolumeStatusXML struct { 238 | XMLName xml.Name `xml:"cliOutput"` 239 | OpRet int `xml:"opRet"` 240 | OpErrno int `xml:"opErrno"` 241 | OpErrstr string `xml:"opErrstr"` 242 | VolStatus struct { 243 | Volumes struct { 244 | Volume []struct { 245 | VolName string `xml:"volName"` 246 | NodeCount int `xml:"nodeCount"` 247 | Node []struct { 248 | Hostname string `xml:"hostname"` 249 | Path string `xml:"path"` 250 | PeerID string `xml:"peerid"` 251 | Status int `xml:"status"` 252 | Port int `xml:"port"` 253 | Ports struct { 254 | TCP int `xml:"tcp"` 255 | RDMA string `xml:"rdma"` 256 | } `xml:"ports"` 257 | Pid int `xml:"pid"` 258 | SizeTotal uint64 `xml:"sizeTotal"` 259 | SizeFree uint64 `xml:"sizeFree"` 260 | Device string `xml:"device"` 261 | BlockSize int `xml:"blockSize"` 262 | MntOptions string `xml:"mntOptions"` 263 | FsName string `xml:"fsName"` 264 | // As of Gluster3.12 this shows filesystem type. Bug? 265 | //InodeSize uint64 `xml:"inodeSize"` 266 | InodesTotal uint64 `xml:"inodesTotal"` 267 | InodesFree uint64 `xml:"inodesFree"` 268 | } `xml:"node"` 269 | } `xml:"volume"` 270 | } `xml:"volumes"` 271 | } `xml:"volStatus"` 272 | } 273 | 274 | // VolumeStatusAllDetailXMLUnmarshall reads bytes.buffer and returns unmarshalled xml 275 | func VolumeStatusAllDetailXMLUnmarshall(cmdOutBuff io.Reader) (VolumeStatusXML, error) { 276 | var vol VolumeStatusXML 277 | b, err := ioutil.ReadAll(cmdOutBuff) 278 | if err != nil { 279 | log.Error(err) 280 | return vol, err 281 | } 282 | err = xml.Unmarshal(b, &vol) 283 | return vol, err 284 | } 285 | 286 | // QuotaLimit is a struct of VolQuota 287 | type QuotaLimit struct { 288 | XMLName xml.Name `xml:"limit"` 289 | Path string `xml:"path"` 290 | HardLimit uint64 `xml:"hard_limit"` 291 | SoftLimitValue uint64 `xml:"soft_limit_value"` 292 | UsedSpace uint64 `xml:"used_space"` 293 | AvailSpace uint64 `xml:"avail_space"` 294 | SlExceeded string `xml:"sl_exceeded"` 295 | HlExceeded string `xml:"hl_exceeded"` 296 | } 297 | 298 | // VolQuota is a struct of VolumeQuotaXML 299 | type VolQuota struct { 300 | XMLName xml.Name `xml:"volQuota"` 301 | QuotaLimits []QuotaLimit `xml:"limit"` 302 | } 303 | 304 | // VolumeQuotaXML XML type of "gluster volume quota list" 305 | type VolumeQuotaXML struct { 306 | XMLName xml.Name `xml:"cliOutput"` 307 | OpRet int `xml:"opRet"` 308 | OpErrno int `xml:"opErrno"` 309 | OpErrstr string `xml:"opErrstr"` 310 | VolQuota VolQuota `xml:"volQuota"` 311 | } 312 | 313 | // VolumeQuotaListXMLUnmarshall function parse "gluster volume quota list" XML output 314 | func VolumeQuotaListXMLUnmarshall(cmdOutBuff io.Reader) (VolumeQuotaXML, error) { 315 | var volQuotaXML VolumeQuotaXML 316 | b, err := ioutil.ReadAll(cmdOutBuff) 317 | if err != nil { 318 | log.Error(err) 319 | return volQuotaXML, err 320 | } 321 | err = xml.Unmarshal(b, &volQuotaXML) 322 | return volQuotaXML, err 323 | } 324 | -------------------------------------------------------------------------------- /structs/xmlStructs_test.go: -------------------------------------------------------------------------------- 1 | package structs 2 | 3 | import ( 4 | "bytes" 5 | "io/ioutil" 6 | "log" 7 | "strconv" 8 | "testing" 9 | ) 10 | 11 | func TestVolumeListXMLUnmarshall(t *testing.T) { 12 | testXMLPath := "../test/gluster_volume_list.xml" 13 | dat, err := ioutil.ReadFile(testXMLPath) 14 | 15 | if err != nil { 16 | t.Errorf("error reading testxml in Path: %v", testXMLPath) 17 | } 18 | volumeList, err := VolumeListXMLUnmarshall(bytes.NewBuffer(dat)) 19 | if err != nil { 20 | t.Fatal(err) 21 | } 22 | 23 | if len(volumeList.VolList.Volume) != 2 { 24 | t.Fatal("Volume List empty") 25 | } 26 | if volumeList.VolList.Count != 2 { 27 | t.Logf("doesn't match volume count of 2: %v", volumeList) 28 | } 29 | 30 | t.Log("gluster volume list test was successful.") 31 | } 32 | 33 | func TestInfoUnmarshall(t *testing.T) { 34 | testXMLPath := "../test/gluster_volume_info.xml" 35 | dat, err := ioutil.ReadFile(testXMLPath) 36 | 37 | if err != nil { 38 | t.Fatalf("error reading testxml in Path: %v", testXMLPath) 39 | } 40 | 41 | glusterVolumeInfo, _ := VolumeInfoXMLUnmarshall(bytes.NewBuffer(dat)) 42 | if glusterVolumeInfo.OpErrno != 0 && glusterVolumeInfo.VolInfo.Volumes.Count == 2 { 43 | t.Fatal("something wrong") 44 | } 45 | for _, volume := range glusterVolumeInfo.VolInfo.Volumes.Volume { 46 | if volume.Status != 1 { 47 | t.Errorf("Status %v expected but got %v", 1, volume.Status) 48 | } 49 | if volume.Name == "" || len(volume.Name) < 1 { 50 | t.Errorf("Not empty name of Volume expected, response was %v", volume.Name) 51 | } 52 | t.Logf("Volume.Name: %v volume.Status: %v", volume.Name, volume.Status) 53 | } 54 | t.Log("gluster volume info test was successful.") 55 | } 56 | 57 | func TestPeerStatusXMLUnmarshall(t *testing.T) { 58 | testXMLPath := "../test/gluster_peer_status.xml" 59 | t.Log("Test xml unmarshal for 'gluster peer status' with file: ", testXMLPath) 60 | dat, err := ioutil.ReadFile(testXMLPath) 61 | if err != nil { 62 | t.Errorf("error reading testxml in Path: %v", testXMLPath) 63 | } 64 | peerStatus, err := PeerStatusXMLUnmarshall(bytes.NewBuffer(dat)) 65 | if err != nil { 66 | t.Fatal(err) 67 | } 68 | 69 | exp := 0 70 | if peerStatus.OpErrno != exp { 71 | t.Fatalf("OpErrno: %v", peerStatus.OpErrno) 72 | } 73 | 74 | exp = 1 75 | if peerStatus.PeerStatus.Peer[0].Connected != exp { 76 | t.Fatalf("Peerstatus is not as expected. Expectel: %v, Current: %v", exp, peerStatus.PeerStatus.Peer[0].Connected) 77 | } 78 | 79 | exp = 3 80 | if len(peerStatus.PeerStatus.Peer) != exp { 81 | t.Fatalf("Number of peers is not 3: %v", len(peerStatus.PeerStatus.Peer)) 82 | } 83 | 84 | expString := "node2.example.local" 85 | if peerStatus.PeerStatus.Peer[0].Hostname != expString { 86 | t.Fatalf("Hostname in Peer doesn't match: %v", peerStatus.PeerStatus.Peer[0].Hostname) 87 | } 88 | 89 | t.Log("gluster peer status test was successful.") 90 | } 91 | 92 | func TestVolumeStatusAllDetailXMLUnmarshall(t *testing.T) { 93 | testXMLPath := "../test/gluster_volume_status_all_detail.xml" 94 | t.Log("Test xml unmarshal for 'gluster volume status all detail' with file: ", testXMLPath) 95 | dat, err := ioutil.ReadFile(testXMLPath) 96 | if err != nil { 97 | t.Errorf("error reading testxml in Path: %v", testXMLPath) 98 | } 99 | volumeStatus, err := VolumeStatusAllDetailXMLUnmarshall(bytes.NewBuffer(dat)) 100 | if err != nil { 101 | t.Error(err) 102 | } 103 | 104 | if volumeStatus.OpErrno != 0 { 105 | t.Error(volumeStatus.OpErrstr) 106 | } 107 | 108 | for _, vol := range volumeStatus.VolStatus.Volumes.Volume { 109 | if vol.NodeCount != 4 { 110 | t.Errorf("nodecount mismatch %v instead of 4", vol.NodeCount) 111 | } 112 | 113 | for _, node := range vol.Node { 114 | if node.BlockSize != 4096 { 115 | t.Errorf("blockSize mismatch %v and 4096 expected", node.BlockSize) 116 | } 117 | 118 | } 119 | 120 | if vol.Node[0].SizeFree != 19517558784 { 121 | t.Errorf("SizeFree doesn't match 19517558784: %v", vol.Node[0].SizeFree) 122 | } 123 | 124 | if vol.Node[0].SizeTotal != 20507914240 { 125 | t.Errorf("SizeFree doesn't match 20507914240: %v", vol.Node[0].SizeTotal) 126 | } 127 | } 128 | 129 | if volumeStatus.VolStatus.Volumes.Volume[0].VolName != "gv_test" { 130 | t.Errorf("VolName of first volume doesn't match gv_test: %v", volumeStatus.VolStatus.Volumes.Volume[0].VolName) 131 | } 132 | 133 | if volumeStatus.VolStatus.Volumes.Volume[1].VolName != "gv_test2" { 134 | t.Errorf("VolName of first volume doesn't match gv_test2: %v", volumeStatus.VolStatus.Volumes.Volume[1].VolName) 135 | } 136 | } 137 | 138 | func TestVolumeProfileGvInfoCumulativeXMLUnmarshall(t *testing.T) { 139 | testXMLPath := "../test/gluster_volume_profile_gv_test_info_cumulative.xml" 140 | t.Log("Test xml unmarshal for 'gluster volume profile gv_test info' with file: ", testXMLPath) 141 | dat, err := ioutil.ReadFile(testXMLPath) 142 | 143 | if err != nil { 144 | t.Fatal("Could not read test data from xml.", err) 145 | } 146 | 147 | profileVolumeCumulative, err := VolumeProfileGvInfoCumulativeXMLUnmarshall(bytes.NewBuffer(dat)) 148 | if err != nil { 149 | t.Fatal(err) 150 | } 151 | 152 | expOpErr := 0 153 | if profileVolumeCumulative.OpErrno != 0 { 154 | t.Errorf("Expected value is %v and got %v", expOpErr, profileVolumeCumulative.OpErrno) 155 | } 156 | 157 | fops := profileVolumeCumulative.VolProfile.Brick[0].CumulativeStats.FopStats.Fop 158 | 159 | expFopLen := 11 160 | fopLen := len(fops) 161 | if fopLen != expFopLen { 162 | t.Errorf("Expected FopLength of %v and got %v.", expFopLen, fopLen) 163 | } 164 | 165 | expFopName := "WRITE" 166 | expFopHits := 58 167 | expAvgLatency := 224.5 168 | expMinLatency := 183.0 169 | expMaxLatency := 807.0 170 | 171 | if fops[0].Name != expFopName { 172 | t.Errorf("expected %v as name and got %v", expFopName, fops[0].Name) 173 | } 174 | 175 | if fops[0].Hits != expFopHits { 176 | t.Errorf("expected %v as name and got %v", expFopHits, fops[0].Hits) 177 | } 178 | 179 | if fops[0].AvgLatency != expAvgLatency { 180 | t.Errorf("expected %v as name and got %v", expAvgLatency, fops[0].AvgLatency) 181 | } 182 | 183 | if fops[0].MinLatency != expMinLatency { 184 | t.Errorf("expected %v as name and got %v", expMinLatency, fops[0].MinLatency) 185 | } 186 | 187 | if fops[0].MaxLatency != expMaxLatency { 188 | t.Errorf("expected %v as name and got %v", expMaxLatency, fops[0].MaxLatency) 189 | } 190 | } 191 | 192 | func getCliBufferHelper(filename string) *bytes.Buffer { 193 | dat, err := ioutil.ReadFile(filename) 194 | if err != nil { 195 | log.Fatal("Could not read test data from xml.", err) 196 | } 197 | return bytes.NewBuffer(dat) 198 | } 199 | 200 | type testPair struct { 201 | path string 202 | expected int 203 | nodeCount int 204 | } 205 | 206 | func TestVolumeHealInfoXMLUnmarshall(t *testing.T) { 207 | var test = []testPair{ 208 | {path: "../test/gluster_volume_heal_info_err_node2.xml", expected: 3, nodeCount: 4}, 209 | } 210 | 211 | for _, c := range test { 212 | cmdOutBuffer := getCliBufferHelper(c.path) 213 | healInfo, err := VolumeHealInfoXMLUnmarshall(cmdOutBuffer) 214 | if err != nil { 215 | t.Error(err) 216 | } 217 | if healInfo.OpErrno != 0 { 218 | t.Error(healInfo.OpErrstr) 219 | } 220 | entriesOutOfSync := 0 221 | if len(healInfo.HealInfo.Bricks.Brick) != c.nodeCount { 222 | t.Error(healInfo.HealInfo.Bricks) 223 | t.Errorf("Expected %v Bricks and len is %v", c.nodeCount, len(healInfo.HealInfo.Bricks.Brick)) 224 | } 225 | for _, brick := range healInfo.HealInfo.Bricks.Brick { 226 | var count int 227 | count, _ = strconv.Atoi(brick.NumberOfEntries) 228 | entriesOutOfSync += count 229 | } 230 | if entriesOutOfSync != c.expected { 231 | t.Errorf("Out of sync entries other than expected: %v and was %v", c.expected, entriesOutOfSync) 232 | } 233 | } 234 | 235 | } 236 | 237 | func TestVolumeQuotaListXMLUnmarshall(t *testing.T) { 238 | testXMLPath := "../test/gluster_volume_quota_list.xml" 239 | nodeCount := 2 240 | dat, err := ioutil.ReadFile(testXMLPath) 241 | 242 | if err != nil { 243 | t.Errorf("error reading testxml in Path: %v", testXMLPath) 244 | } 245 | volumeQuotaXML, err := VolumeQuotaListXMLUnmarshall(bytes.NewBuffer(dat)) 246 | if err != nil { 247 | t.Error(err) 248 | } 249 | 250 | if volumeQuotaXML.OpErrno != 0 { 251 | t.Error(volumeQuotaXML.OpErrstr) 252 | } 253 | nbLimits := len(volumeQuotaXML.VolQuota.QuotaLimits) 254 | if nbLimits != nodeCount { 255 | t.Errorf("Expected %v Limits and len is %v", nodeCount, nbLimits) 256 | } 257 | 258 | for _, limit := range volumeQuotaXML.VolQuota.QuotaLimits { 259 | if limit.Path == "/foo" { 260 | if limit.AvailSpace != 10309258240 { 261 | t.Errorf( 262 | "Expected %v for available space in path %v, got %v", 263 | 1811939328, 264 | limit.Path, 265 | limit.AvailSpace, 266 | ) 267 | } 268 | } 269 | } 270 | 271 | } 272 | -------------------------------------------------------------------------------- /test/gluster_peer_status.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 0 4 | 0 5 | 6 | 7 | 8 | f6fa44e7-5139-4f6e-8404-6d2ce7d66231 9 | node2.example.local 10 | 11 | node2.example.local 12 | 13 | 1 14 | 3 15 | Peer in Cluster 16 | 17 | 18 | 1d5d9c25-211c-4db6-8fd6-274cf3774d88 19 | node4.example.local 20 | 21 | node4.example.local 22 | 23 | 1 24 | 3 25 | Peer in Cluster 26 | 27 | 28 | 073c4354-f8eb-4474-95b3-c2bc235ca44d 29 | node3.example.local 30 | 31 | node3.example.local 32 | 33 | 1 34 | 3 35 | Peer in Cluster 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /test/gluster_volume_heal_info.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | node1.example.com:/mnt/gluster/gv_test 7 | Connected 8 | 0 9 | 10 | 11 | node2.example.com:/mnt/gluster/gv_test 12 | Connected 13 | 0 14 | 15 | 16 | node3.example.com:/mnt/gluster/gv_test 17 | Connected 18 | 0 19 | 20 | 21 | 22 | 0 23 | 0 24 | 25 | 26 | -------------------------------------------------------------------------------- /test/gluster_volume_heal_info_err_node1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | node1.example.com:/mnt/gluster/gv_test 7 | <gfid:5ff0a22c-f8f1-4dc1-86a2-7db417fc75da> 8 | <gfid:e5c164c8-a121-4286-b339-879fb743e105> 9 | / 10 | <gfid:bc3071f1-807a-49bf-90eb-997e6bd558fe> 11 | <gfid:2d5db4f0-3ec1-43d9-8a7d-98da2eecac02> 12 | Connected 13 | 5 14 | 15 | 16 | node2.example.com:/mnt/gluster/gv_test 17 | Transport endpoint is not connected 18 | - 19 | 20 | 21 | node3.example.com:/mnt/gluster/gv_test 22 | Transport endpoint is not connected 23 | - 24 | 25 | 26 | node4.example.com:/mnt/gluster/gv_test 27 | Transport endpoint is not connected 28 | - 29 | 30 | 31 | 32 | 0 33 | 0 34 | 35 | 36 | -------------------------------------------------------------------------------- /test/gluster_volume_heal_info_err_node2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | node1.example.com:/mnt/gluster/gv_test 7 | Transport endpoint is not connected 8 | - 9 | 10 | 11 | node2.example.com:/mnt/gluster/gv_test 12 | <gfid:2e4ef09b-bc83-48f9-8d0e-109d5033dd66> 13 | <gfid:a7d55aba-7c7a-4fb9-9a72-ac14587ced82> 14 | / 15 | Connected 16 | 3 17 | 18 | 19 | node3.example.com:/mnt/gluster/gv_test 20 | Transport endpoint is not connected 21 | - 22 | 23 | 24 | node4.example.com:/mnt/gluster/gv_test 25 | Transport endpoint is not connected 26 | - 27 | 28 | 29 | 30 | 0 31 | 0 32 | 33 | 34 | -------------------------------------------------------------------------------- /test/gluster_volume_info.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 0 4 | 0 5 | 6 | 7 | 8 | 9 | gv_cluster 10 | 841dceb0-ffff-4005-9463-4addcfd2ffff 11 | 1 12 | Started 13 | 0 14 | 4 15 | 4 16 | 1 17 | 4 18 | 0 19 | 0 20 | 0 21 | 2 22 | Replicate 23 | 0 24 | 25 | 26 | host1.example.local:/mnt/gluster/gv_clusterhost1.example.local:/mnt/gluster/gv_clustera049c424-ffff-4436-abd4-ef3fcfffffa0 27 | host2.example.local:/mnt/gluster/gv_clusterhost2.example.local:/mnt/gluster/gv_clusterf6fa44e7-ffff-4f6e-8404-6d2cefffff10 28 | host3.example.local:/mnt/gluster/gv_clusterhost3.example.local:/mnt/gluster/gv_cluster073c4354-ffff-4474-95b3-c2bc2fffffd0 29 | host4.example.local:/mnt/gluster/gv_clusterhost4.example.local:/mnt/gluster/gv_cluster1d5d9c25-ffff-4db6-8fd6-274cffffff80 30 | 31 | 5 32 | 33 | 37 | 41 | 45 | 49 | 53 | 54 | 55 | 56 | gv_test 57 | 592c9a08-3b02-482f-ab40-87372760cb47 58 | 1 59 | Started 60 | 0 61 | 4 62 | 4 63 | 1 64 | 4 65 | 0 66 | 0 67 | 0 68 | 2 69 | Replicate 70 | 0 71 | 72 | 73 | host1.example.local:/mnt/gluster/gv_testhost1.example.local:/mnt/gluster/gv_testa049c424-ffff-4436-abd4-ef3fcfffffa0 74 | host2.example.local:/mnt/gluster/gv_testhost2.example.local:/mnt/gluster/gv_testf6fa44e7-ffff-4f6e-8404-6d2cefffff10 75 | host3.example.local:/mnt/gluster/gv_testhost3.example.local:/mnt/gluster/gv_test073c4354-ffff-4474-95b3-c2bc2fffffd0 76 | host4.example.local:/mnt/gluster/gv_testhost4.example.local:/mnt/gluster/gv_test1d5d9c25-ffff-4db6-8fd6-274cffffff80 77 | 78 | 7 79 | 80 | 84 | 88 | 92 | 96 | 100 | 104 | 108 | 109 | 110 | 2 111 | 112 | 113 | -------------------------------------------------------------------------------- /test/gluster_volume_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 0 4 | 0 5 | 6 | 7 | 2 8 | gv_cluster 9 | gv_test 10 | 11 | 12 | -------------------------------------------------------------------------------- /test/gluster_volume_profile_gv_test_info.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 0 4 | 0 5 | 6 | 7 | gv_test 8 | 3 9 | 4 10 | 11 | node2.example.local:/mnt/gluster/gv_test 12 | 13 | 14 | 15 | 1 16 | 0 17 | 0 18 | 19 | 20 | 2 21 | 0 22 | 0 23 | 24 | 25 | 4 26 | 0 27 | 0 28 | 29 | 30 | 8 31 | 0 32 | 0 33 | 34 | 35 | 16 36 | 0 37 | 0 38 | 39 | 40 | 32 41 | 0 42 | 0 43 | 44 | 45 | 64 46 | 0 47 | 0 48 | 49 | 50 | 128 51 | 0 52 | 0 53 | 54 | 55 | 256 56 | 0 57 | 0 58 | 59 | 60 | 512 61 | 0 62 | 0 63 | 64 | 65 | 1024 66 | 0 67 | 0 68 | 69 | 70 | 2048 71 | 0 72 | 0 73 | 74 | 75 | 4096 76 | 0 77 | 0 78 | 79 | 80 | 8192 81 | 0 82 | 1 83 | 84 | 85 | 16384 86 | 0 87 | 0 88 | 89 | 90 | 32768 91 | 0 92 | 0 93 | 94 | 95 | 65536 96 | 0 97 | 0 98 | 99 | 100 | 131072 101 | 800 102 | 4800 103 | 104 | 105 | 262144 106 | 0 107 | 0 108 | 109 | 110 | 524288 111 | 0 112 | 0 113 | 114 | 115 | 1048576 116 | 0 117 | 0 118 | 119 | 120 | 2097152 121 | 0 122 | 0 123 | 124 | 125 | 4194304 126 | 0 127 | 0 128 | 129 | 130 | 8388608 131 | 0 132 | 0 133 | 134 | 135 | 16777216 136 | 0 137 | 0 138 | 139 | 140 | 33554432 141 | 0 142 | 0 143 | 144 | 145 | 67108864 146 | 0 147 | 0 148 | 149 | 150 | 134217728 151 | 0 152 | 0 153 | 154 | 155 | 268435456 156 | 0 157 | 0 158 | 159 | 160 | 536870912 161 | 0 162 | 0 163 | 164 | 165 | 1073741824 166 | 0 167 | 0 168 | 169 | 170 | 2147483648 171 | 0 172 | 0 173 | 174 | 175 | 176 | 177 | UNLINK 178 | 2 179 | 9177.500000 180 | 122.000000 181 | 18233.000000 182 | 183 | 184 | TRUNCATE 185 | 3 186 | 6715.000000 187 | 161.000000 188 | 19806.000000 189 | 190 | 191 | OPEN 192 | 3 193 | 94.333333 194 | 61.000000 195 | 137.000000 196 | 197 | 198 | READ 199 | 787 200 | 395.040359 201 | 76.000000 202 | 5531.000000 203 | 204 | 205 | WRITE 206 | 4801 207 | 252.654239 208 | 137.000000 209 | 66007.000000 210 | 211 | 212 | STATFS 213 | 110 214 | 141.272727 215 | 29.000000 216 | 1688.000000 217 | 218 | 219 | FLUSH 220 | 11 221 | 56.181818 222 | 20.000000 223 | 311.000000 224 | 225 | 226 | GETXATTR 227 | 610 228 | 118.919672 229 | 18.000000 230 | 1322.000000 231 | 232 | 233 | OPENDIR 234 | 461 235 | 5.310195 236 | 3.000000 237 | 88.000000 238 | 239 | 240 | CREATE 241 | 4 242 | 257.250000 243 | 215.000000 244 | 293.000000 245 | 246 | 247 | FSTAT 248 | 396 249 | 75.128788 250 | 52.000000 251 | 2829.000000 252 | 253 | 254 | LOOKUP 255 | 554 256 | 64.261733 257 | 12.000000 258 | 1213.000000 259 | 260 | 261 | READDIR 262 | 900 263 | 1498.366667 264 | 158.000000 265 | 11431.000000 266 | 267 | 268 | INODELK 269 | 6 270 | 37.333333 271 | 28.000000 272 | 64.000000 273 | 274 | 275 | FINODELK 276 | 14 277 | 35.285714 278 | 26.000000 279 | 49.000000 280 | 281 | 282 | ENTRYLK 283 | 12 284 | 30.500000 285 | 21.000000 286 | 75.000000 287 | 288 | 289 | XATTROP 290 | 6 291 | 157.000000 292 | 110.000000 293 | 195.000000 294 | 295 | 296 | FXATTROP 297 | 32 298 | 132.406250 299 | 70.000000 300 | 571.000000 301 | 302 | 303 | READDIRP 304 | 8 305 | 177.500000 306 | 42.000000 307 | 334.000000 308 | 309 | 310 | 89145 311 | 104857600 312 | 629156392 313 | 314 | 315 | 316 | 317 | 1 318 | 0 319 | 0 320 | 321 | 322 | 2 323 | 0 324 | 0 325 | 326 | 327 | 4 328 | 0 329 | 0 330 | 331 | 332 | 8 333 | 0 334 | 0 335 | 336 | 337 | 16 338 | 0 339 | 0 340 | 341 | 342 | 32 343 | 0 344 | 0 345 | 346 | 347 | 64 348 | 0 349 | 0 350 | 351 | 352 | 128 353 | 0 354 | 0 355 | 356 | 357 | 256 358 | 0 359 | 0 360 | 361 | 362 | 512 363 | 0 364 | 0 365 | 366 | 367 | 1024 368 | 0 369 | 0 370 | 371 | 372 | 2048 373 | 0 374 | 0 375 | 376 | 377 | 4096 378 | 0 379 | 0 380 | 381 | 382 | 8192 383 | 0 384 | 1 385 | 386 | 387 | 16384 388 | 0 389 | 0 390 | 391 | 392 | 32768 393 | 0 394 | 0 395 | 396 | 397 | 65536 398 | 0 399 | 0 400 | 401 | 402 | 131072 403 | 0 404 | 0 405 | 406 | 407 | 262144 408 | 0 409 | 0 410 | 411 | 412 | 524288 413 | 0 414 | 0 415 | 416 | 417 | 1048576 418 | 0 419 | 0 420 | 421 | 422 | 2097152 423 | 0 424 | 0 425 | 426 | 427 | 4194304 428 | 0 429 | 0 430 | 431 | 432 | 8388608 433 | 0 434 | 0 435 | 436 | 437 | 16777216 438 | 0 439 | 0 440 | 441 | 442 | 33554432 443 | 0 444 | 0 445 | 446 | 447 | 67108864 448 | 0 449 | 0 450 | 451 | 452 | 134217728 453 | 0 454 | 0 455 | 456 | 457 | 268435456 458 | 0 459 | 0 460 | 461 | 462 | 536870912 463 | 0 464 | 0 465 | 466 | 467 | 1073741824 468 | 0 469 | 0 470 | 471 | 472 | 2147483648 473 | 0 474 | 0 475 | 476 | 477 | 478 | 479 | TRUNCATE 480 | 1 481 | 161.000000 482 | 161.000000 483 | 161.000000 484 | 485 | 486 | WRITE 487 | 1 488 | 137.000000 489 | 137.000000 490 | 137.000000 491 | 492 | 493 | STATFS 494 | 8 495 | 95.250000 496 | 40.000000 497 | 234.000000 498 | 499 | 500 | FLUSH 501 | 1 502 | 25.000000 503 | 25.000000 504 | 25.000000 505 | 506 | 507 | OPENDIR 508 | 2 509 | 66.500000 510 | 50.000000 511 | 83.000000 512 | 513 | 514 | LOOKUP 515 | 8 516 | 220.125000 517 | 149.000000 518 | 267.000000 519 | 520 | 521 | INODELK 522 | 2 523 | 50.000000 524 | 36.000000 525 | 64.000000 526 | 527 | 528 | FINODELK 529 | 2 530 | 48.000000 531 | 47.000000 532 | 49.000000 533 | 534 | 535 | XATTROP 536 | 2 537 | 184.000000 538 | 173.000000 539 | 195.000000 540 | 541 | 542 | FXATTROP 543 | 2 544 | 179.500000 545 | 169.000000 546 | 190.000000 547 | 548 | 549 | READDIRP 550 | 4 551 | 176.750000 552 | 42.000000 553 | 334.000000 554 | 555 | 556 | 55 557 | 0 558 | 10792 559 | 560 | 561 | 562 | node4.example.local:/mnt/gluster/gv_test 563 | 564 | 565 | 566 | 1 567 | 0 568 | 0 569 | 570 | 571 | 2 572 | 0 573 | 0 574 | 575 | 576 | 4 577 | 0 578 | 0 579 | 580 | 581 | 8 582 | 0 583 | 0 584 | 585 | 586 | 16 587 | 0 588 | 0 589 | 590 | 591 | 32 592 | 0 593 | 0 594 | 595 | 596 | 64 597 | 0 598 | 0 599 | 600 | 601 | 128 602 | 0 603 | 0 604 | 605 | 606 | 256 607 | 0 608 | 0 609 | 610 | 611 | 512 612 | 0 613 | 0 614 | 615 | 616 | 1024 617 | 0 618 | 0 619 | 620 | 621 | 2048 622 | 0 623 | 0 624 | 625 | 626 | 4096 627 | 0 628 | 0 629 | 630 | 631 | 8192 632 | 0 633 | 1 634 | 635 | 636 | 16384 637 | 0 638 | 0 639 | 640 | 641 | 32768 642 | 0 643 | 0 644 | 645 | 646 | 65536 647 | 0 648 | 0 649 | 650 | 651 | 131072 652 | 0 653 | 4800 654 | 655 | 656 | 262144 657 | 0 658 | 0 659 | 660 | 661 | 524288 662 | 0 663 | 0 664 | 665 | 666 | 1048576 667 | 0 668 | 0 669 | 670 | 671 | 2097152 672 | 0 673 | 0 674 | 675 | 676 | 4194304 677 | 0 678 | 0 679 | 680 | 681 | 8388608 682 | 0 683 | 0 684 | 685 | 686 | 16777216 687 | 0 688 | 0 689 | 690 | 691 | 33554432 692 | 0 693 | 0 694 | 695 | 696 | 67108864 697 | 0 698 | 0 699 | 700 | 701 | 134217728 702 | 0 703 | 0 704 | 705 | 706 | 268435456 707 | 0 708 | 0 709 | 710 | 711 | 536870912 712 | 0 713 | 0 714 | 715 | 716 | 1073741824 717 | 0 718 | 0 719 | 720 | 721 | 2147483648 722 | 0 723 | 0 724 | 725 | 726 | 727 | 728 | UNLINK 729 | 2 730 | 4085.000000 731 | 127.000000 732 | 8043.000000 733 | 734 | 735 | TRUNCATE 736 | 3 737 | 6629.666667 738 | 162.000000 739 | 19556.000000 740 | 741 | 742 | OPEN 743 | 3 744 | 71.333333 745 | 58.000000 746 | 84.000000 747 | 748 | 749 | WRITE 750 | 4801 751 | 203.053114 752 | 128.000000 753 | 8662.000000 754 | 755 | 756 | STATFS 757 | 216 758 | 79.564815 759 | 26.000000 760 | 2287.000000 761 | 762 | 763 | FLUSH 764 | 11 765 | 24.727273 766 | 19.000000 767 | 52.000000 768 | 769 | 770 | GETXATTR 771 | 621 772 | 140.355878 773 | 16.000000 774 | 2240.000000 775 | 776 | 777 | OPENDIR 778 | 467 779 | 5.066381 780 | 3.000000 781 | 50.000000 782 | 783 | 784 | CREATE 785 | 4 786 | 4192.000000 787 | 206.000000 788 | 16085.000000 789 | 790 | 791 | LOOKUP 792 | 573 793 | 80.369983 794 | 12.000000 795 | 3876.000000 796 | 797 | 798 | READDIR 799 | 912 800 | 1620.757675 801 | 112.000000 802 | 12148.000000 803 | 804 | 805 | INODELK 806 | 6 807 | 32.000000 808 | 28.000000 809 | 36.000000 810 | 811 | 812 | FINODELK 813 | 14 814 | 33.142857 815 | 22.000000 816 | 50.000000 817 | 818 | 819 | ENTRYLK 820 | 12 821 | 28.500000 822 | 21.000000 823 | 42.000000 824 | 825 | 826 | XATTROP 827 | 6 828 | 146.333333 829 | 116.000000 830 | 164.000000 831 | 832 | 833 | FXATTROP 834 | 32 835 | 116.375000 836 | 67.000000 837 | 230.000000 838 | 839 | 840 | 89921 841 | 0 842 | 629156392 843 | 844 | 845 | 846 | 847 | 1 848 | 0 849 | 0 850 | 851 | 852 | 2 853 | 0 854 | 0 855 | 856 | 857 | 4 858 | 0 859 | 0 860 | 861 | 862 | 8 863 | 0 864 | 0 865 | 866 | 867 | 16 868 | 0 869 | 0 870 | 871 | 872 | 32 873 | 0 874 | 0 875 | 876 | 877 | 64 878 | 0 879 | 0 880 | 881 | 882 | 128 883 | 0 884 | 0 885 | 886 | 887 | 256 888 | 0 889 | 0 890 | 891 | 892 | 512 893 | 0 894 | 0 895 | 896 | 897 | 1024 898 | 0 899 | 0 900 | 901 | 902 | 2048 903 | 0 904 | 0 905 | 906 | 907 | 4096 908 | 0 909 | 0 910 | 911 | 912 | 8192 913 | 0 914 | 1 915 | 916 | 917 | 16384 918 | 0 919 | 0 920 | 921 | 922 | 32768 923 | 0 924 | 0 925 | 926 | 927 | 65536 928 | 0 929 | 0 930 | 931 | 932 | 131072 933 | 0 934 | 0 935 | 936 | 937 | 262144 938 | 0 939 | 0 940 | 941 | 942 | 524288 943 | 0 944 | 0 945 | 946 | 947 | 1048576 948 | 0 949 | 0 950 | 951 | 952 | 2097152 953 | 0 954 | 0 955 | 956 | 957 | 4194304 958 | 0 959 | 0 960 | 961 | 962 | 8388608 963 | 0 964 | 0 965 | 966 | 967 | 16777216 968 | 0 969 | 0 970 | 971 | 972 | 33554432 973 | 0 974 | 0 975 | 976 | 977 | 67108864 978 | 0 979 | 0 980 | 981 | 982 | 134217728 983 | 0 984 | 0 985 | 986 | 987 | 268435456 988 | 0 989 | 0 990 | 991 | 992 | 536870912 993 | 0 994 | 0 995 | 996 | 997 | 1073741824 998 | 0 999 | 0 1000 | 1001 | 1002 | 2147483648 1003 | 0 1004 | 0 1005 | 1006 | 1007 | 1008 | 1009 | TRUNCATE 1010 | 1 1011 | 162.000000 1012 | 162.000000 1013 | 162.000000 1014 | 1015 | 1016 | WRITE 1017 | 1 1018 | 128.000000 1019 | 128.000000 1020 | 128.000000 1021 | 1022 | 1023 | STATFS 1024 | 16 1025 | 71.937500 1026 | 35.000000 1027 | 286.000000 1028 | 1029 | 1030 | FLUSH 1031 | 1 1032 | 22.000000 1033 | 22.000000 1034 | 22.000000 1035 | 1036 | 1037 | OPENDIR 1038 | 2 1039 | 41.500000 1040 | 38.000000 1041 | 45.000000 1042 | 1043 | 1044 | LOOKUP 1045 | 8 1046 | 175.625000 1047 | 118.000000 1048 | 260.000000 1049 | 1050 | 1051 | INODELK 1052 | 2 1053 | 30.000000 1054 | 28.000000 1055 | 32.000000 1056 | 1057 | 1058 | FINODELK 1059 | 2 1060 | 38.000000 1061 | 26.000000 1062 | 50.000000 1063 | 1064 | 1065 | XATTROP 1066 | 2 1067 | 146.000000 1068 | 130.000000 1069 | 162.000000 1070 | 1071 | 1072 | FXATTROP 1073 | 2 1074 | 132.000000 1075 | 90.000000 1076 | 174.000000 1077 | 1078 | 1079 | 55 1080 | 0 1081 | 10792 1082 | 1083 | 1084 | 1085 | node1.example.local:/mnt/gluster/gv_test 1086 | 1087 | 1088 | 1089 | 1 1090 | 0 1091 | 0 1092 | 1093 | 1094 | 2 1095 | 0 1096 | 0 1097 | 1098 | 1099 | 4 1100 | 0 1101 | 0 1102 | 1103 | 1104 | 8 1105 | 0 1106 | 0 1107 | 1108 | 1109 | 16 1110 | 0 1111 | 0 1112 | 1113 | 1114 | 32 1115 | 0 1116 | 0 1117 | 1118 | 1119 | 64 1120 | 0 1121 | 0 1122 | 1123 | 1124 | 128 1125 | 0 1126 | 0 1127 | 1128 | 1129 | 256 1130 | 0 1131 | 0 1132 | 1133 | 1134 | 512 1135 | 0 1136 | 0 1137 | 1138 | 1139 | 1024 1140 | 0 1141 | 0 1142 | 1143 | 1144 | 2048 1145 | 0 1146 | 0 1147 | 1148 | 1149 | 4096 1150 | 0 1151 | 0 1152 | 1153 | 1154 | 8192 1155 | 0 1156 | 1 1157 | 1158 | 1159 | 16384 1160 | 0 1161 | 0 1162 | 1163 | 1164 | 32768 1165 | 0 1166 | 0 1167 | 1168 | 1169 | 65536 1170 | 0 1171 | 0 1172 | 1173 | 1174 | 131072 1175 | 1600 1176 | 4800 1177 | 1178 | 1179 | 262144 1180 | 0 1181 | 0 1182 | 1183 | 1184 | 524288 1185 | 0 1186 | 0 1187 | 1188 | 1189 | 1048576 1190 | 0 1191 | 0 1192 | 1193 | 1194 | 2097152 1195 | 0 1196 | 0 1197 | 1198 | 1199 | 4194304 1200 | 0 1201 | 0 1202 | 1203 | 1204 | 8388608 1205 | 0 1206 | 0 1207 | 1208 | 1209 | 16777216 1210 | 0 1211 | 0 1212 | 1213 | 1214 | 33554432 1215 | 0 1216 | 0 1217 | 1218 | 1219 | 67108864 1220 | 0 1221 | 0 1222 | 1223 | 1224 | 134217728 1225 | 0 1226 | 0 1227 | 1228 | 1229 | 268435456 1230 | 0 1231 | 0 1232 | 1233 | 1234 | 536870912 1235 | 0 1236 | 0 1237 | 1238 | 1239 | 1073741824 1240 | 0 1241 | 0 1242 | 1243 | 1244 | 2147483648 1245 | 0 1246 | 0 1247 | 1248 | 1249 | 1250 | 1251 | UNLINK 1252 | 2 1253 | 9282.500000 1254 | 168.000000 1255 | 18397.000000 1256 | 1257 | 1258 | TRUNCATE 1259 | 3 1260 | 6211.333333 1261 | 143.000000 1262 | 18272.000000 1263 | 1264 | 1265 | OPEN 1266 | 3 1267 | 175.333333 1268 | 78.000000 1269 | 296.000000 1270 | 1271 | 1272 | READ 1273 | 1602 1274 | 288.580178 1275 | 70.000000 1276 | 4607.000000 1277 | 1278 | 1279 | WRITE 1280 | 4801 1281 | 310.998959 1282 | 139.000000 1283 | 6844.000000 1284 | 1285 | 1286 | STATFS 1287 | 108 1288 | 161.231481 1289 | 30.000000 1290 | 2191.000000 1291 | 1292 | 1293 | FLUSH 1294 | 11 1295 | 33.272727 1296 | 18.000000 1297 | 81.000000 1298 | 1299 | 1300 | GETXATTR 1301 | 601 1302 | 127.663894 1303 | 20.000000 1304 | 1942.000000 1305 | 1306 | 1307 | OPENDIR 1308 | 458 1309 | 5.340611 1310 | 3.000000 1311 | 71.000000 1312 | 1313 | 1314 | CREATE 1315 | 4 1316 | 4279.500000 1317 | 214.000000 1318 | 16294.000000 1319 | 1320 | 1321 | FSTAT 1322 | 671 1323 | 101.582712 1324 | 32.000000 1325 | 3014.000000 1326 | 1327 | 1328 | LOOKUP 1329 | 542 1330 | 69.680812 1331 | 12.000000 1332 | 1116.000000 1333 | 1334 | 1335 | READDIR 1336 | 894 1337 | 1543.983221 1338 | 140.000000 1339 | 9401.000000 1340 | 1341 | 1342 | INODELK 1343 | 6 1344 | 61.166667 1345 | 26.000000 1346 | 106.000000 1347 | 1348 | 1349 | FINODELK 1350 | 14 1351 | 74.357143 1352 | 29.000000 1353 | 247.000000 1354 | 1355 | 1356 | ENTRYLK 1357 | 12 1358 | 102.583333 1359 | 24.000000 1360 | 325.000000 1361 | 1362 | 1363 | XATTROP 1364 | 6 1365 | 172.666667 1366 | 118.000000 1367 | 227.000000 1368 | 1369 | 1370 | FXATTROP 1371 | 32 1372 | 374.593750 1373 | 66.000000 1374 | 3758.000000 1375 | 1376 | 1377 | READDIRP 1378 | 14 1379 | 158.357143 1380 | 42.000000 1381 | 350.000000 1382 | 1383 | 1384 | 89128 1385 | 209715200 1386 | 629156392 1387 | 1388 | 1389 | 1390 | 1391 | 1 1392 | 0 1393 | 0 1394 | 1395 | 1396 | 2 1397 | 0 1398 | 0 1399 | 1400 | 1401 | 4 1402 | 0 1403 | 0 1404 | 1405 | 1406 | 8 1407 | 0 1408 | 0 1409 | 1410 | 1411 | 16 1412 | 0 1413 | 0 1414 | 1415 | 1416 | 32 1417 | 0 1418 | 0 1419 | 1420 | 1421 | 64 1422 | 0 1423 | 0 1424 | 1425 | 1426 | 128 1427 | 0 1428 | 0 1429 | 1430 | 1431 | 256 1432 | 0 1433 | 0 1434 | 1435 | 1436 | 512 1437 | 0 1438 | 0 1439 | 1440 | 1441 | 1024 1442 | 0 1443 | 0 1444 | 1445 | 1446 | 2048 1447 | 0 1448 | 0 1449 | 1450 | 1451 | 4096 1452 | 0 1453 | 0 1454 | 1455 | 1456 | 8192 1457 | 0 1458 | 1 1459 | 1460 | 1461 | 16384 1462 | 0 1463 | 0 1464 | 1465 | 1466 | 32768 1467 | 0 1468 | 0 1469 | 1470 | 1471 | 65536 1472 | 0 1473 | 0 1474 | 1475 | 1476 | 131072 1477 | 0 1478 | 0 1479 | 1480 | 1481 | 262144 1482 | 0 1483 | 0 1484 | 1485 | 1486 | 524288 1487 | 0 1488 | 0 1489 | 1490 | 1491 | 1048576 1492 | 0 1493 | 0 1494 | 1495 | 1496 | 2097152 1497 | 0 1498 | 0 1499 | 1500 | 1501 | 4194304 1502 | 0 1503 | 0 1504 | 1505 | 1506 | 8388608 1507 | 0 1508 | 0 1509 | 1510 | 1511 | 16777216 1512 | 0 1513 | 0 1514 | 1515 | 1516 | 33554432 1517 | 0 1518 | 0 1519 | 1520 | 1521 | 67108864 1522 | 0 1523 | 0 1524 | 1525 | 1526 | 134217728 1527 | 0 1528 | 0 1529 | 1530 | 1531 | 268435456 1532 | 0 1533 | 0 1534 | 1535 | 1536 | 536870912 1537 | 0 1538 | 0 1539 | 1540 | 1541 | 1073741824 1542 | 0 1543 | 0 1544 | 1545 | 1546 | 2147483648 1547 | 0 1548 | 0 1549 | 1550 | 1551 | 1552 | 1553 | TRUNCATE 1554 | 1 1555 | 143.000000 1556 | 143.000000 1557 | 143.000000 1558 | 1559 | 1560 | WRITE 1561 | 1 1562 | 139.000000 1563 | 139.000000 1564 | 139.000000 1565 | 1566 | 1567 | STATFS 1568 | 8 1569 | 86.750000 1570 | 42.000000 1571 | 244.000000 1572 | 1573 | 1574 | FLUSH 1575 | 1 1576 | 22.000000 1577 | 22.000000 1578 | 22.000000 1579 | 1580 | 1581 | OPENDIR 1582 | 2 1583 | 40.500000 1584 | 32.000000 1585 | 49.000000 1586 | 1587 | 1588 | LOOKUP 1589 | 8 1590 | 175.500000 1591 | 124.000000 1592 | 250.000000 1593 | 1594 | 1595 | INODELK 1596 | 2 1597 | 29.000000 1598 | 26.000000 1599 | 32.000000 1600 | 1601 | 1602 | FINODELK 1603 | 2 1604 | 38.500000 1605 | 29.000000 1606 | 48.000000 1607 | 1608 | 1609 | XATTROP 1610 | 2 1611 | 142.500000 1612 | 118.000000 1613 | 167.000000 1614 | 1615 | 1616 | FXATTROP 1617 | 2 1618 | 147.000000 1619 | 107.000000 1620 | 187.000000 1621 | 1622 | 1623 | 55 1624 | 0 1625 | 10792 1626 | 1627 | 1628 | 1629 | node3.example.local:/mnt/gluster/gv_test 1630 | 1631 | 1632 | 1633 | 1 1634 | 0 1635 | 0 1636 | 1637 | 1638 | 2 1639 | 0 1640 | 0 1641 | 1642 | 1643 | 4 1644 | 0 1645 | 0 1646 | 1647 | 1648 | 8 1649 | 0 1650 | 0 1651 | 1652 | 1653 | 16 1654 | 0 1655 | 0 1656 | 1657 | 1658 | 32 1659 | 0 1660 | 0 1661 | 1662 | 1663 | 64 1664 | 0 1665 | 0 1666 | 1667 | 1668 | 128 1669 | 0 1670 | 0 1671 | 1672 | 1673 | 256 1674 | 0 1675 | 0 1676 | 1677 | 1678 | 512 1679 | 0 1680 | 0 1681 | 1682 | 1683 | 1024 1684 | 0 1685 | 0 1686 | 1687 | 1688 | 2048 1689 | 0 1690 | 0 1691 | 1692 | 1693 | 4096 1694 | 0 1695 | 0 1696 | 1697 | 1698 | 8192 1699 | 0 1700 | 1 1701 | 1702 | 1703 | 16384 1704 | 0 1705 | 0 1706 | 1707 | 1708 | 32768 1709 | 0 1710 | 0 1711 | 1712 | 1713 | 65536 1714 | 0 1715 | 0 1716 | 1717 | 1718 | 131072 1719 | 0 1720 | 4800 1721 | 1722 | 1723 | 262144 1724 | 0 1725 | 0 1726 | 1727 | 1728 | 524288 1729 | 0 1730 | 0 1731 | 1732 | 1733 | 1048576 1734 | 0 1735 | 0 1736 | 1737 | 1738 | 2097152 1739 | 0 1740 | 0 1741 | 1742 | 1743 | 4194304 1744 | 0 1745 | 0 1746 | 1747 | 1748 | 8388608 1749 | 0 1750 | 0 1751 | 1752 | 1753 | 16777216 1754 | 0 1755 | 0 1756 | 1757 | 1758 | 33554432 1759 | 0 1760 | 0 1761 | 1762 | 1763 | 67108864 1764 | 0 1765 | 0 1766 | 1767 | 1768 | 134217728 1769 | 0 1770 | 0 1771 | 1772 | 1773 | 268435456 1774 | 0 1775 | 0 1776 | 1777 | 1778 | 536870912 1779 | 0 1780 | 0 1781 | 1782 | 1783 | 1073741824 1784 | 0 1785 | 0 1786 | 1787 | 1788 | 2147483648 1789 | 0 1790 | 0 1791 | 1792 | 1793 | 1794 | 1795 | UNLINK 1796 | 2 1797 | 146.000000 1798 | 123.000000 1799 | 169.000000 1800 | 1801 | 1802 | TRUNCATE 1803 | 3 1804 | 6578.666667 1805 | 136.000000 1806 | 19425.000000 1807 | 1808 | 1809 | OPEN 1810 | 3 1811 | 72.000000 1812 | 60.000000 1813 | 81.000000 1814 | 1815 | 1816 | WRITE 1817 | 4801 1818 | 210.004999 1819 | 134.000000 1820 | 9372.000000 1821 | 1822 | 1823 | STATFS 1824 | 215 1825 | 74.800000 1826 | 23.000000 1827 | 2540.000000 1828 | 1829 | 1830 | FLUSH 1831 | 11 1832 | 22.909091 1833 | 20.000000 1834 | 40.000000 1835 | 1836 | 1837 | GETXATTR 1838 | 621 1839 | 141.286634 1840 | 17.000000 1841 | 4609.000000 1842 | 1843 | 1844 | OPENDIR 1845 | 467 1846 | 4.912206 1847 | 3.000000 1848 | 51.000000 1849 | 1850 | 1851 | CREATE 1852 | 4 1853 | 221.750000 1854 | 211.000000 1855 | 233.000000 1856 | 1857 | 1858 | LOOKUP 1859 | 573 1860 | 63.846422 1861 | 13.000000 1862 | 1451.000000 1863 | 1864 | 1865 | READDIR 1866 | 912 1867 | 1461.053728 1868 | 170.000000 1869 | 5042.000000 1870 | 1871 | 1872 | INODELK 1873 | 6 1874 | 34.833333 1875 | 29.000000 1876 | 43.000000 1877 | 1878 | 1879 | FINODELK 1880 | 16 1881 | 55.187500 1882 | 23.000000 1883 | 347.000000 1884 | 1885 | 1886 | ENTRYLK 1887 | 12 1888 | 28.250000 1889 | 22.000000 1890 | 39.000000 1891 | 1892 | 1893 | XATTROP 1894 | 6 1895 | 142.833333 1896 | 115.000000 1897 | 168.000000 1898 | 1899 | 1900 | FXATTROP 1901 | 32 1902 | 117.562500 1903 | 70.000000 1904 | 336.000000 1905 | 1906 | 1907 | 89922 1908 | 0 1909 | 629156392 1910 | 1911 | 1912 | 1913 | 1914 | 1 1915 | 0 1916 | 0 1917 | 1918 | 1919 | 2 1920 | 0 1921 | 0 1922 | 1923 | 1924 | 4 1925 | 0 1926 | 0 1927 | 1928 | 1929 | 8 1930 | 0 1931 | 0 1932 | 1933 | 1934 | 16 1935 | 0 1936 | 0 1937 | 1938 | 1939 | 32 1940 | 0 1941 | 0 1942 | 1943 | 1944 | 64 1945 | 0 1946 | 0 1947 | 1948 | 1949 | 128 1950 | 0 1951 | 0 1952 | 1953 | 1954 | 256 1955 | 0 1956 | 0 1957 | 1958 | 1959 | 512 1960 | 0 1961 | 0 1962 | 1963 | 1964 | 1024 1965 | 0 1966 | 0 1967 | 1968 | 1969 | 2048 1970 | 0 1971 | 0 1972 | 1973 | 1974 | 4096 1975 | 0 1976 | 0 1977 | 1978 | 1979 | 8192 1980 | 0 1981 | 1 1982 | 1983 | 1984 | 16384 1985 | 0 1986 | 0 1987 | 1988 | 1989 | 32768 1990 | 0 1991 | 0 1992 | 1993 | 1994 | 65536 1995 | 0 1996 | 0 1997 | 1998 | 1999 | 131072 2000 | 0 2001 | 0 2002 | 2003 | 2004 | 262144 2005 | 0 2006 | 0 2007 | 2008 | 2009 | 524288 2010 | 0 2011 | 0 2012 | 2013 | 2014 | 1048576 2015 | 0 2016 | 0 2017 | 2018 | 2019 | 2097152 2020 | 0 2021 | 0 2022 | 2023 | 2024 | 4194304 2025 | 0 2026 | 0 2027 | 2028 | 2029 | 8388608 2030 | 0 2031 | 0 2032 | 2033 | 2034 | 16777216 2035 | 0 2036 | 0 2037 | 2038 | 2039 | 33554432 2040 | 0 2041 | 0 2042 | 2043 | 2044 | 67108864 2045 | 0 2046 | 0 2047 | 2048 | 2049 | 134217728 2050 | 0 2051 | 0 2052 | 2053 | 2054 | 268435456 2055 | 0 2056 | 0 2057 | 2058 | 2059 | 536870912 2060 | 0 2061 | 0 2062 | 2063 | 2064 | 1073741824 2065 | 0 2066 | 0 2067 | 2068 | 2069 | 2147483648 2070 | 0 2071 | 0 2072 | 2073 | 2074 | 2075 | 2076 | TRUNCATE 2077 | 1 2078 | 136.000000 2079 | 136.000000 2080 | 136.000000 2081 | 2082 | 2083 | WRITE 2084 | 1 2085 | 134.000000 2086 | 134.000000 2087 | 134.000000 2088 | 2089 | 2090 | STATFS 2091 | 16 2092 | 48.312500 2093 | 34.000000 2094 | 104.000000 2095 | 2096 | 2097 | FLUSH 2098 | 1 2099 | 20.000000 2100 | 20.000000 2101 | 20.000000 2102 | 2103 | 2104 | OPENDIR 2105 | 2 2106 | 40.500000 2107 | 32.000000 2108 | 49.000000 2109 | 2110 | 2111 | LOOKUP 2112 | 8 2113 | 174.875000 2114 | 119.000000 2115 | 254.000000 2116 | 2117 | 2118 | INODELK 2119 | 2 2120 | 37.000000 2121 | 31.000000 2122 | 43.000000 2123 | 2124 | 2125 | FINODELK 2126 | 2 2127 | 45.000000 2128 | 27.000000 2129 | 63.000000 2130 | 2131 | 2132 | XATTROP 2133 | 2 2134 | 142.000000 2135 | 116.000000 2136 | 168.000000 2137 | 2138 | 2139 | FXATTROP 2140 | 2 2141 | 145.000000 2142 | 110.000000 2143 | 180.000000 2144 | 2145 | 2146 | 55 2147 | 0 2148 | 10792 2149 | 2150 | 2151 | 2152 | 2153 | -------------------------------------------------------------------------------- /test/gluster_volume_profile_gv_test_info_cumulative.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 0 4 | 0 5 | 6 | 7 | gv_test 8 | 3 9 | 4 10 | 11 | node1.example.local:/mnt/gluster/gv_test 12 | 13 | 14 | 15 | 1 16 | 0 17 | 0 18 | 19 | 20 | 2 21 | 0 22 | 0 23 | 24 | 25 | 4 26 | 0 27 | 0 28 | 29 | 30 | 8 31 | 0 32 | 0 33 | 34 | 35 | 16 36 | 0 37 | 0 38 | 39 | 40 | 32 41 | 0 42 | 0 43 | 44 | 45 | 64 46 | 0 47 | 0 48 | 49 | 50 | 128 51 | 0 52 | 0 53 | 54 | 55 | 256 56 | 0 57 | 0 58 | 59 | 60 | 512 61 | 0 62 | 0 63 | 64 | 65 | 1024 66 | 0 67 | 0 68 | 69 | 70 | 2048 71 | 0 72 | 0 73 | 74 | 75 | 4096 76 | 0 77 | 0 78 | 79 | 80 | 8192 81 | 0 82 | 0 83 | 84 | 85 | 16384 86 | 0 87 | 0 88 | 89 | 90 | 32768 91 | 0 92 | 0 93 | 94 | 95 | 65536 96 | 0 97 | 1 98 | 99 | 100 | 131072 101 | 0 102 | 57 103 | 104 | 105 | 262144 106 | 0 107 | 0 108 | 109 | 110 | 524288 111 | 0 112 | 0 113 | 114 | 115 | 1048576 116 | 0 117 | 0 118 | 119 | 120 | 2097152 121 | 0 122 | 0 123 | 124 | 125 | 4194304 126 | 0 127 | 0 128 | 129 | 130 | 8388608 131 | 0 132 | 0 133 | 134 | 135 | 16777216 136 | 0 137 | 0 138 | 139 | 140 | 33554432 141 | 0 142 | 0 143 | 144 | 145 | 67108864 146 | 0 147 | 0 148 | 149 | 150 | 134217728 151 | 0 152 | 0 153 | 154 | 155 | 268435456 156 | 0 157 | 0 158 | 159 | 160 | 536870912 161 | 0 162 | 0 163 | 164 | 165 | 1073741824 166 | 0 167 | 0 168 | 169 | 170 | 2147483648 171 | 0 172 | 0 173 | 174 | 175 | 176 | 177 | WRITE 178 | 58 179 | 224.500000 180 | 183.000000 181 | 807.000000 182 | 183 | 184 | STATFS 185 | 3 186 | 44.666667 187 | 32.000000 188 | 69.000000 189 | 190 | 191 | FLUSH 192 | 1 193 | 117.000000 194 | 117.000000 195 | 117.000000 196 | 197 | 198 | GETXATTR 199 | 123 200 | 148.658537 201 | 17.000000 202 | 1154.000000 203 | 204 | 205 | OPENDIR 206 | 87 207 | 4.091954 208 | 3.000000 209 | 6.000000 210 | 211 | 212 | CREATE 213 | 1 214 | 23259.000000 215 | 23259.000000 216 | 23259.000000 217 | 218 | 219 | LOOKUP 220 | 119 221 | 68.495798 222 | 14.000000 223 | 332.000000 224 | 225 | 226 | READDIR 227 | 174 228 | 1601.942529 229 | 195.000000 230 | 4566.000000 231 | 232 | 233 | FINODELK 234 | 2 235 | 80.000000 236 | 76.000000 237 | 84.000000 238 | 239 | 240 | ENTRYLK 241 | 2 242 | 54.000000 243 | 51.000000 244 | 57.000000 245 | 246 | 247 | FXATTROP 248 | 2 249 | 211.500000 250 | 192.000000 251 | 231.000000 252 | 253 | 254 | 16932 255 | 0 256 | 7590710 257 | 258 | 259 | 260 | node3.example.local:/mnt/gluster/gv_test 261 | 262 | 263 | 264 | 1 265 | 0 266 | 0 267 | 268 | 269 | 2 270 | 0 271 | 0 272 | 273 | 274 | 4 275 | 0 276 | 0 277 | 278 | 279 | 8 280 | 0 281 | 0 282 | 283 | 284 | 16 285 | 0 286 | 0 287 | 288 | 289 | 32 290 | 0 291 | 0 292 | 293 | 294 | 64 295 | 0 296 | 0 297 | 298 | 299 | 128 300 | 0 301 | 0 302 | 303 | 304 | 256 305 | 0 306 | 0 307 | 308 | 309 | 512 310 | 0 311 | 0 312 | 313 | 314 | 1024 315 | 0 316 | 0 317 | 318 | 319 | 2048 320 | 0 321 | 0 322 | 323 | 324 | 4096 325 | 0 326 | 0 327 | 328 | 329 | 8192 330 | 0 331 | 0 332 | 333 | 334 | 16384 335 | 0 336 | 0 337 | 338 | 339 | 32768 340 | 0 341 | 0 342 | 343 | 344 | 65536 345 | 0 346 | 1 347 | 348 | 349 | 131072 350 | 0 351 | 57 352 | 353 | 354 | 262144 355 | 0 356 | 0 357 | 358 | 359 | 524288 360 | 0 361 | 0 362 | 363 | 364 | 1048576 365 | 0 366 | 0 367 | 368 | 369 | 2097152 370 | 0 371 | 0 372 | 373 | 374 | 4194304 375 | 0 376 | 0 377 | 378 | 379 | 8388608 380 | 0 381 | 0 382 | 383 | 384 | 16777216 385 | 0 386 | 0 387 | 388 | 389 | 33554432 390 | 0 391 | 0 392 | 393 | 394 | 67108864 395 | 0 396 | 0 397 | 398 | 399 | 134217728 400 | 0 401 | 0 402 | 403 | 404 | 268435456 405 | 0 406 | 0 407 | 408 | 409 | 536870912 410 | 0 411 | 0 412 | 413 | 414 | 1073741824 415 | 0 416 | 0 417 | 418 | 419 | 2147483648 420 | 0 421 | 0 422 | 423 | 424 | 425 | 426 | WRITE 427 | 58 428 | 193.706897 429 | 176.000000 430 | 289.000000 431 | 432 | 433 | STATFS 434 | 5 435 | 57.000000 436 | 29.000000 437 | 116.000000 438 | 439 | 440 | FLUSH 441 | 1 442 | 33.000000 443 | 33.000000 444 | 33.000000 445 | 446 | 447 | GETXATTR 448 | 126 449 | 143.888889 450 | 22.000000 451 | 3943.000000 452 | 453 | 454 | OPENDIR 455 | 87 456 | 4.057471 457 | 3.000000 458 | 7.000000 459 | 460 | 461 | CREATE 462 | 1 463 | 24722.000000 464 | 24722.000000 465 | 24722.000000 466 | 467 | 468 | LOOKUP 469 | 125 470 | 73.832000 471 | 12.000000 472 | 1324.000000 473 | 474 | 475 | READDIR 476 | 174 477 | 1528.844828 478 | 109.000000 479 | 5545.000000 480 | 481 | 482 | FINODELK 483 | 2 484 | 30.500000 485 | 27.000000 486 | 34.000000 487 | 488 | 489 | ENTRYLK 490 | 2 491 | 33.000000 492 | 26.000000 493 | 40.000000 494 | 495 | 496 | FXATTROP 497 | 2 498 | 147.500000 499 | 129.000000 500 | 166.000000 501 | 502 | 503 | 16938 504 | 0 505 | 7590710 506 | 507 | 508 | 509 | node2.example.local:/mnt/gluster/gv_test 510 | 511 | 512 | 513 | 1 514 | 0 515 | 0 516 | 517 | 518 | 2 519 | 0 520 | 0 521 | 522 | 523 | 4 524 | 0 525 | 0 526 | 527 | 528 | 8 529 | 0 530 | 0 531 | 532 | 533 | 16 534 | 0 535 | 0 536 | 537 | 538 | 32 539 | 0 540 | 0 541 | 542 | 543 | 64 544 | 0 545 | 0 546 | 547 | 548 | 128 549 | 0 550 | 0 551 | 552 | 553 | 256 554 | 0 555 | 0 556 | 557 | 558 | 512 559 | 0 560 | 0 561 | 562 | 563 | 1024 564 | 0 565 | 0 566 | 567 | 568 | 2048 569 | 0 570 | 0 571 | 572 | 573 | 4096 574 | 0 575 | 0 576 | 577 | 578 | 8192 579 | 0 580 | 0 581 | 582 | 583 | 16384 584 | 0 585 | 0 586 | 587 | 588 | 32768 589 | 0 590 | 0 591 | 592 | 593 | 65536 594 | 0 595 | 1 596 | 597 | 598 | 131072 599 | 0 600 | 57 601 | 602 | 603 | 262144 604 | 0 605 | 0 606 | 607 | 608 | 524288 609 | 0 610 | 0 611 | 612 | 613 | 1048576 614 | 0 615 | 0 616 | 617 | 618 | 2097152 619 | 0 620 | 0 621 | 622 | 623 | 4194304 624 | 0 625 | 0 626 | 627 | 628 | 8388608 629 | 0 630 | 0 631 | 632 | 633 | 16777216 634 | 0 635 | 0 636 | 637 | 638 | 33554432 639 | 0 640 | 0 641 | 642 | 643 | 67108864 644 | 0 645 | 0 646 | 647 | 648 | 134217728 649 | 0 650 | 0 651 | 652 | 653 | 268435456 654 | 0 655 | 0 656 | 657 | 658 | 536870912 659 | 0 660 | 0 661 | 662 | 663 | 1073741824 664 | 0 665 | 0 666 | 667 | 668 | 2147483648 669 | 0 670 | 0 671 | 672 | 673 | 674 | 675 | WRITE 676 | 58 677 | 192.810345 678 | 174.000000 679 | 481.000000 680 | 681 | 682 | STATFS 683 | 4 684 | 45.750000 685 | 33.000000 686 | 60.000000 687 | 688 | 689 | FLUSH 690 | 1 691 | 48.000000 692 | 48.000000 693 | 48.000000 694 | 695 | 696 | GETXATTR 697 | 129 698 | 112.093023 699 | 15.000000 700 | 1332.000000 701 | 702 | 703 | OPENDIR 704 | 90 705 | 4.077778 706 | 3.000000 707 | 7.000000 708 | 709 | 710 | CREATE 711 | 1 712 | 24856.000000 713 | 24856.000000 714 | 24856.000000 715 | 716 | 717 | LOOKUP 718 | 129 719 | 59.139535 720 | 12.000000 721 | 251.000000 722 | 723 | 724 | READDIR 725 | 180 726 | 1375.411111 727 | 97.000000 728 | 2466.000000 729 | 730 | 731 | FINODELK 732 | 2 733 | 35.000000 734 | 33.000000 735 | 37.000000 736 | 737 | 738 | ENTRYLK 739 | 2 740 | 27.000000 741 | 26.000000 742 | 28.000000 743 | 744 | 745 | FXATTROP 746 | 2 747 | 146.000000 748 | 127.000000 749 | 165.000000 750 | 751 | 752 | 16939 753 | 0 754 | 7590710 755 | 756 | 757 | 758 | node4.example.local:/mnt/gluster/gv_test 759 | 760 | 761 | 762 | 1 763 | 0 764 | 0 765 | 766 | 767 | 2 768 | 0 769 | 0 770 | 771 | 772 | 4 773 | 0 774 | 0 775 | 776 | 777 | 8 778 | 0 779 | 0 780 | 781 | 782 | 16 783 | 0 784 | 0 785 | 786 | 787 | 32 788 | 0 789 | 0 790 | 791 | 792 | 64 793 | 0 794 | 0 795 | 796 | 797 | 128 798 | 0 799 | 0 800 | 801 | 802 | 256 803 | 0 804 | 0 805 | 806 | 807 | 512 808 | 0 809 | 0 810 | 811 | 812 | 1024 813 | 0 814 | 0 815 | 816 | 817 | 2048 818 | 0 819 | 0 820 | 821 | 822 | 4096 823 | 0 824 | 0 825 | 826 | 827 | 8192 828 | 0 829 | 0 830 | 831 | 832 | 16384 833 | 0 834 | 0 835 | 836 | 837 | 32768 838 | 0 839 | 0 840 | 841 | 842 | 65536 843 | 0 844 | 1 845 | 846 | 847 | 131072 848 | 0 849 | 57 850 | 851 | 852 | 262144 853 | 0 854 | 0 855 | 856 | 857 | 524288 858 | 0 859 | 0 860 | 861 | 862 | 1048576 863 | 0 864 | 0 865 | 866 | 867 | 2097152 868 | 0 869 | 0 870 | 871 | 872 | 4194304 873 | 0 874 | 0 875 | 876 | 877 | 8388608 878 | 0 879 | 0 880 | 881 | 882 | 16777216 883 | 0 884 | 0 885 | 886 | 887 | 33554432 888 | 0 889 | 0 890 | 891 | 892 | 67108864 893 | 0 894 | 0 895 | 896 | 897 | 134217728 898 | 0 899 | 0 900 | 901 | 902 | 268435456 903 | 0 904 | 0 905 | 906 | 907 | 536870912 908 | 0 909 | 0 910 | 911 | 912 | 1073741824 913 | 0 914 | 0 915 | 916 | 917 | 2147483648 918 | 0 919 | 0 920 | 921 | 922 | 923 | 924 | WRITE 925 | 58 926 | 192.500000 927 | 177.000000 928 | 285.000000 929 | 930 | 931 | STATFS 932 | 2 933 | 61.000000 934 | 32.000000 935 | 90.000000 936 | 937 | 938 | FLUSH 939 | 1 940 | 43.000000 941 | 43.000000 942 | 43.000000 943 | 944 | 945 | GETXATTR 946 | 122 947 | 112.975410 948 | 18.000000 949 | 870.000000 950 | 951 | 952 | OPENDIR 953 | 87 954 | 4.218391 955 | 3.000000 956 | 8.000000 957 | 958 | 959 | CREATE 960 | 1 961 | 20577.000000 962 | 20577.000000 963 | 20577.000000 964 | 965 | 966 | LOOKUP 967 | 117 968 | 124.914530 969 | 13.000000 970 | 5066.000000 971 | 972 | 973 | READDIR 974 | 174 975 | 1491.948276 976 | 132.000000 977 | 3731.000000 978 | 979 | 980 | FINODELK 981 | 2 982 | 31.000000 983 | 30.000000 984 | 32.000000 985 | 986 | 987 | ENTRYLK 988 | 2 989 | 26.000000 990 | 25.000000 991 | 27.000000 992 | 993 | 994 | FXATTROP 995 | 2 996 | 148.000000 997 | 125.000000 998 | 171.000000 999 | 1000 | 1001 | 16930 1002 | 0 1003 | 7590710 1004 | 1005 | 1006 | 1007 | 1008 | -------------------------------------------------------------------------------- /test/gluster_volume_quota_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 0 3 | 0 4 | 5 | 6 | 7 | /foo 8 | 10737418240 9 | 80% 10 | 8589934592 11 | 428160000 12 | 10309258240 13 | No 14 | No 15 | 16 | 17 | /bar 18 | 2147483648 19 | 80% 20 | 1717986918 21 | 335544320 22 | 1811939328 23 | No 24 | No 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /test/gluster_volume_status_all_detail.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 0 4 | 0 5 | 6 | 7 | 8 | 9 | gv_test 10 | 4 11 | 12 | node1.example.local 13 | /mnt/gluster/gv_test 14 | a049c424-bd82-4436-abd4-ef3fc37c76ba 15 | 1 16 | 49153 17 | 18 | 49153 19 | N/A 20 | 21 | 1342 22 | 20507914240 23 | 19517558784 24 | /dev/loop0 25 | 4096 26 | rw,relatime,data=ordered 27 | ext4 28 | 29 | 30 | node2.example.local 31 | /mnt/gluster/gv_test 32 | f6fa44e7-5139-4f6e-8404-6d2ce7d66231 33 | 1 34 | 49153 35 | 36 | 49153 37 | N/A 38 | 39 | 1303 40 | 20507914240 41 | 19517558784 42 | /dev/loop0 43 | 4096 44 | rw,relatime,data=ordered 45 | ext4 46 | 47 | 48 | node3.example.local 49 | /mnt/gluster/gv_test 50 | 073c4354-f8eb-4474-95b3-c2bc235ca44d 51 | 1 52 | 49153 53 | 54 | 49153 55 | N/A 56 | 57 | 1284 58 | 20507914240 59 | 19517558784 60 | /dev/loop0 61 | 4096 62 | rw,relatime,data=ordered 63 | ext4 64 | 65 | 66 | node4.example.local 67 | /mnt/gluster/gv_test 68 | 1d5d9c25-211c-4db6-8fd6-274cf3774d88 69 | 1 70 | 49153 71 | 72 | 49153 73 | N/A 74 | 75 | 1312 76 | 20507914240 77 | 19517566976 78 | /dev/loop0 79 | 4096 80 | rw,relatime,data=ordered 81 | ext4 82 | 83 | 84 | 85 | gv_test2 86 | 4 87 | 88 | node1.example.local 89 | /mnt/gluster/gv_test2 90 | a049c424-bd82-4436-abd4-ef3fc37c76ba 91 | 1 92 | 49153 93 | 94 | 49153 95 | N/A 96 | 97 | 1342 98 | 20507914240 99 | 19517558784 100 | /dev/loop0 101 | 4096 102 | rw,relatime,data=ordered 103 | ext4 104 | 105 | 106 | node2.example.local 107 | /mnt/gluster/gv_test2 108 | f6fa44e7-5139-4f6e-8404-6d2ce7d66231 109 | 1 110 | 49153 111 | 112 | 49153 113 | N/A 114 | 115 | 1303 116 | 20507914240 117 | 19517558784 118 | /dev/loop0 119 | 4096 120 | rw,relatime,data=ordered 121 | ext4 122 | 123 | 124 | node3.example.local 125 | /mnt/gluster/gv_test2 126 | 073c4354-f8eb-4474-95b3-c2bc235ca44d 127 | 1 128 | 49153 129 | 130 | 49153 131 | N/A 132 | 133 | 1284 134 | 20507914240 135 | 19517558784 136 | /dev/loop0 137 | 4096 138 | rw,relatime,data=ordered 139 | ext4 140 | 141 | 142 | node4.example.local 143 | /mnt/gluster/gv_test2 144 | 1d5d9c25-211c-4db6-8fd6-274cf3774d88 145 | 1 146 | 49153 147 | 148 | 49153 149 | N/A 150 | 151 | 1312 152 | 20507914240 153 | 19517566976 154 | /dev/loop0 155 | 4096 156 | rw,relatime,data=ordered 157 | ext4 158 | 159 | 160 | 161 | 162 | 163 | --------------------------------------------------------------------------------