mirror of
https://github.com/arangodb/kube-arangodb.git
synced 2024-12-14 11:57:37 +00:00
Adding deployment details view
This commit is contained in:
parent
81b98028b3
commit
a65aa3ecef
15 changed files with 791 additions and 112 deletions
File diff suppressed because one or more lines are too long
352
dashboard/package-lock.json
generated
352
dashboard/package-lock.json
generated
|
@ -4,6 +4,15 @@
|
|||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"@babel/helper-module-imports": {
|
||||
"version": "7.0.0-beta.40",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.0.0-beta.40.tgz",
|
||||
"integrity": "sha512-QFOskAKWbqJSBbGIl/Y1igJI4mW0A+wD5NFqsgDJj85KSvj/dHM4wNGIeqCi85nN9aMa4DgTBBrzUK4zSMsN2Q==",
|
||||
"requires": {
|
||||
"@babel/types": "7.0.0-beta.40",
|
||||
"lodash": "^4.2.0"
|
||||
}
|
||||
},
|
||||
"@babel/runtime": {
|
||||
"version": "7.0.0-beta.51",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.0.0-beta.51.tgz",
|
||||
|
@ -20,12 +29,98 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"@babel/types": {
|
||||
"version": "7.0.0-beta.40",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.0.0-beta.40.tgz",
|
||||
"integrity": "sha512-uXCGCzTgMZxcSUzutCPtZmXbVC+cvENgS2e0tRuhn+Y1hZnMb8IHP0Trq7Q2MB/eFmG5pKrAeTIUfQIe5kA4Tg==",
|
||||
"requires": {
|
||||
"esutils": "^2.0.2",
|
||||
"lodash": "^4.2.0",
|
||||
"to-fast-properties": "^2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"to-fast-properties": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
|
||||
"integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@emotion/babel-utils": {
|
||||
"version": "0.6.5",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/babel-utils/-/babel-utils-0.6.5.tgz",
|
||||
"integrity": "sha1-NNeETrUy0Rdcj8cBdb63TQcb++s=",
|
||||
"requires": {
|
||||
"@emotion/hash": "^0.6.3",
|
||||
"@emotion/memoize": "^0.6.3",
|
||||
"@emotion/serialize": "^0.8.3",
|
||||
"convert-source-map": "^1.5.1",
|
||||
"find-root": "^1.1.0",
|
||||
"source-map": "^0.7.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"source-map": {
|
||||
"version": "0.7.3",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
|
||||
"integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@emotion/hash": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.6.3.tgz",
|
||||
"integrity": "sha1-DnpWBGJvxsbUrEBhovWsgNUCYqQ="
|
||||
},
|
||||
"@emotion/is-prop-valid": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.6.3.tgz",
|
||||
"integrity": "sha1-sElW4tZVAn/ojGI0Zp/XBk+wccw=",
|
||||
"requires": {
|
||||
"@emotion/memoize": "^0.6.3"
|
||||
}
|
||||
},
|
||||
"@emotion/memoize": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.6.3.tgz",
|
||||
"integrity": "sha1-ZDeaHWr2+NT+i9bv6dnoJOpLItg="
|
||||
},
|
||||
"@emotion/serialize": {
|
||||
"version": "0.8.3",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-0.8.3.tgz",
|
||||
"integrity": "sha1-D61Vual/lSPmsf1vtvdLbLQcf4s=",
|
||||
"requires": {
|
||||
"@emotion/hash": "^0.6.3",
|
||||
"@emotion/memoize": "^0.6.3",
|
||||
"@emotion/unitless": "^0.6.3",
|
||||
"@emotion/utils": "^0.7.1"
|
||||
}
|
||||
},
|
||||
"@emotion/stylis": {
|
||||
"version": "0.6.10",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.6.10.tgz",
|
||||
"integrity": "sha1-fTIeY568i6I6zlmQwg6U3Ou4890="
|
||||
},
|
||||
"@emotion/unitless": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.6.3.tgz",
|
||||
"integrity": "sha1-ZWguaKgnAccO77ONf5QaLAv6kN4="
|
||||
},
|
||||
"@emotion/utils": {
|
||||
"version": "0.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-0.7.1.tgz",
|
||||
"integrity": "sha1-5E5ZbQPJ8WujsSetMzqKByvLWgo="
|
||||
},
|
||||
"abab": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/abab/-/abab-1.0.4.tgz",
|
||||
"integrity": "sha1-X6rZwsB/YN12dw9xzwJbYqY8/U4=",
|
||||
"dev": true
|
||||
},
|
||||
"abbrev": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
||||
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
|
||||
},
|
||||
"accepts": {
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz",
|
||||
|
@ -286,7 +381,6 @@
|
|||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
|
||||
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"sprintf-js": "~1.0.2"
|
||||
}
|
||||
|
@ -801,6 +895,32 @@
|
|||
"babel-types": "^6.26.0"
|
||||
}
|
||||
},
|
||||
"babel-plugin-emotion": {
|
||||
"version": "9.2.4",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-emotion/-/babel-plugin-emotion-9.2.4.tgz",
|
||||
"integrity": "sha1-pOVKgJf2ugbLvHqQY5J6+v6f5zo=",
|
||||
"requires": {
|
||||
"@babel/helper-module-imports": "7.0.0-beta.40",
|
||||
"@emotion/babel-utils": "^0.6.4",
|
||||
"@emotion/hash": "^0.6.2",
|
||||
"@emotion/memoize": "^0.6.1",
|
||||
"@emotion/stylis": "^0.6.10",
|
||||
"babel-plugin-macros": "^2.0.0",
|
||||
"babel-plugin-syntax-jsx": "^6.18.0",
|
||||
"convert-source-map": "^1.5.0",
|
||||
"find-root": "^1.1.0",
|
||||
"mkdirp": "^0.5.1",
|
||||
"source-map": "^0.5.7",
|
||||
"touch": "^1.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"source-map": {
|
||||
"version": "0.5.7",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
|
||||
"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
|
||||
}
|
||||
}
|
||||
},
|
||||
"babel-plugin-istanbul": {
|
||||
"version": "4.1.6",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.6.tgz",
|
||||
|
@ -819,6 +939,55 @@
|
|||
"integrity": "sha1-r+3IU70/jcNUjqZx++adA8wsF2c=",
|
||||
"dev": true
|
||||
},
|
||||
"babel-plugin-macros": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.2.2.tgz",
|
||||
"integrity": "sha512-wq6DYqjNmSPskGyhOeRIbmuvLtsHTfc6ROtGqapTttIGL1RoQmM3V5N8aJiDxPaw3/fveIsVspF51E3V7qTOMQ==",
|
||||
"requires": {
|
||||
"cosmiconfig": "^4.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"cosmiconfig": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-4.0.0.tgz",
|
||||
"integrity": "sha512-6e5vDdrXZD+t5v0L8CrurPeybg4Fmf+FCSYxXKYVAqLUtyCSbuyqE059d0kDthTNRzKVjL7QMgNpEUlsoYH3iQ==",
|
||||
"requires": {
|
||||
"is-directory": "^0.3.1",
|
||||
"js-yaml": "^3.9.0",
|
||||
"parse-json": "^4.0.0",
|
||||
"require-from-string": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"esprima": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz",
|
||||
"integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw=="
|
||||
},
|
||||
"js-yaml": {
|
||||
"version": "3.12.0",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz",
|
||||
"integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==",
|
||||
"requires": {
|
||||
"argparse": "^1.0.7",
|
||||
"esprima": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"parse-json": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
|
||||
"integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
|
||||
"requires": {
|
||||
"error-ex": "^1.3.1",
|
||||
"json-parse-better-errors": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"require-from-string": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
|
||||
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"babel-plugin-syntax-async-functions": {
|
||||
"version": "6.13.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz",
|
||||
|
@ -852,8 +1021,7 @@
|
|||
"babel-plugin-syntax-jsx": {
|
||||
"version": "6.18.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz",
|
||||
"integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=",
|
||||
"dev": true
|
||||
"integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY="
|
||||
},
|
||||
"babel-plugin-syntax-object-rest-spread": {
|
||||
"version": "6.13.0",
|
||||
|
@ -2393,8 +2561,7 @@
|
|||
"convert-source-map": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz",
|
||||
"integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=",
|
||||
"dev": true
|
||||
"integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU="
|
||||
},
|
||||
"cookie": {
|
||||
"version": "0.3.1",
|
||||
|
@ -2466,6 +2633,28 @@
|
|||
"elliptic": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"create-emotion": {
|
||||
"version": "9.2.4",
|
||||
"resolved": "https://registry.npmjs.org/create-emotion/-/create-emotion-9.2.4.tgz",
|
||||
"integrity": "sha1-CkN59r8HCMVP4mv81ra9NZLozyM=",
|
||||
"requires": {
|
||||
"@emotion/hash": "^0.6.2",
|
||||
"@emotion/memoize": "^0.6.1",
|
||||
"@emotion/stylis": "^0.6.10",
|
||||
"@emotion/unitless": "^0.6.2",
|
||||
"csstype": "^2.5.2",
|
||||
"stylis": "^3.5.0",
|
||||
"stylis-rule-sheet": "^0.0.10"
|
||||
}
|
||||
},
|
||||
"create-emotion-styled": {
|
||||
"version": "9.2.3",
|
||||
"resolved": "https://registry.npmjs.org/create-emotion-styled/-/create-emotion-styled-9.2.3.tgz",
|
||||
"integrity": "sha1-F/sTs65MFl6m5aETVquLnKHa2cU=",
|
||||
"requires": {
|
||||
"@emotion/is-prop-valid": "^0.6.1"
|
||||
}
|
||||
},
|
||||
"create-error-class": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz",
|
||||
|
@ -2781,6 +2970,11 @@
|
|||
"cssom": "0.3.x"
|
||||
}
|
||||
},
|
||||
"csstype": {
|
||||
"version": "2.5.5",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-2.5.5.tgz",
|
||||
"integrity": "sha512-EGMjeoiN3aqEX5u/cyH5mSdGBDGdLcCQvcEcBWNGFSPXKd9uOTIeVG91YQ22OxI44DKpvI+4C7VUSmEpsHWJaA=="
|
||||
},
|
||||
"currently-unhandled": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
|
||||
|
@ -3209,6 +3403,15 @@
|
|||
"integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=",
|
||||
"dev": true
|
||||
},
|
||||
"emotion": {
|
||||
"version": "9.2.4",
|
||||
"resolved": "https://registry.npmjs.org/emotion/-/emotion-9.2.4.tgz",
|
||||
"integrity": "sha1-ATnnzBVLKEX0ua+qmW3U3hO7kOM=",
|
||||
"requires": {
|
||||
"babel-plugin-emotion": "^9.2.4",
|
||||
"create-emotion": "^9.2.4"
|
||||
}
|
||||
},
|
||||
"encodeurl": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
||||
|
@ -3254,7 +3457,6 @@
|
|||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
|
||||
"integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-arrayish": "^0.2.1"
|
||||
}
|
||||
|
@ -3750,8 +3952,7 @@
|
|||
"esutils": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
|
||||
"integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
|
||||
"dev": true
|
||||
"integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs="
|
||||
},
|
||||
"etag": {
|
||||
"version": "1.8.1",
|
||||
|
@ -4260,6 +4461,11 @@
|
|||
"pkg-dir": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"find-root": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz",
|
||||
"integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng=="
|
||||
},
|
||||
"find-up": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
|
||||
|
@ -5250,6 +5456,28 @@
|
|||
"integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=",
|
||||
"dev": true
|
||||
},
|
||||
"history": {
|
||||
"version": "4.7.2",
|
||||
"resolved": "https://registry.npmjs.org/history/-/history-4.7.2.tgz",
|
||||
"integrity": "sha512-1zkBRWW6XweO0NBcjiphtVJVsIQ+SXF29z9DVkceeaSLVMFXHool+fdCZD4spDCfZJCILPILc3bm7Bc+HRi0nA==",
|
||||
"requires": {
|
||||
"invariant": "^2.2.1",
|
||||
"loose-envify": "^1.2.0",
|
||||
"resolve-pathname": "^2.2.0",
|
||||
"value-equal": "^0.4.0",
|
||||
"warning": "^3.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"warning": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz",
|
||||
"integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=",
|
||||
"requires": {
|
||||
"loose-envify": "^1.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"hmac-drbg": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
|
||||
|
@ -5261,6 +5489,11 @@
|
|||
"minimalistic-crypto-utils": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"hoist-non-react-statics": {
|
||||
"version": "2.5.5",
|
||||
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz",
|
||||
"integrity": "sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw=="
|
||||
},
|
||||
"home-or-tmp": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz",
|
||||
|
@ -5766,7 +5999,6 @@
|
|||
"version": "2.2.4",
|
||||
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
|
||||
"integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"loose-envify": "^1.0.0"
|
||||
}
|
||||
|
@ -5818,8 +6050,7 @@
|
|||
"is-arrayish": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
|
||||
"integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
|
||||
"dev": true
|
||||
"integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0="
|
||||
},
|
||||
"is-binary-path": {
|
||||
"version": "1.0.1",
|
||||
|
@ -5908,8 +6139,7 @@
|
|||
"is-directory": {
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz",
|
||||
"integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=",
|
||||
"dev": true
|
||||
"integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE="
|
||||
},
|
||||
"is-dotfile": {
|
||||
"version": "1.0.3",
|
||||
|
@ -6991,6 +7221,11 @@
|
|||
"integrity": "sha512-QLPs8Dj7lnf3e3QYS1zkCo+4ZwqOiF9d/nZnYozTISxXWCfNs9yuky5rJw4/W34s7POaNlbZmQGaB5NiXCbP4w==",
|
||||
"dev": true
|
||||
},
|
||||
"json-parse-better-errors": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
|
||||
"integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw=="
|
||||
},
|
||||
"json-schema": {
|
||||
"version": "0.2.3",
|
||||
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
|
||||
|
@ -7558,8 +7793,7 @@
|
|||
"minimist": {
|
||||
"version": "0.0.8",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
|
||||
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
|
||||
"dev": true
|
||||
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
|
||||
},
|
||||
"mixin-deep": {
|
||||
"version": "1.3.1",
|
||||
|
@ -7586,7 +7820,6 @@
|
|||
"version": "0.5.1",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
|
||||
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "0.0.8"
|
||||
}
|
||||
|
@ -7750,6 +7983,14 @@
|
|||
"which": "^1.3.0"
|
||||
}
|
||||
},
|
||||
"nopt": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz",
|
||||
"integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=",
|
||||
"requires": {
|
||||
"abbrev": "1"
|
||||
}
|
||||
},
|
||||
"normalize-package-data": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
|
||||
|
@ -8190,7 +8431,6 @@
|
|||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz",
|
||||
"integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"isarray": "0.0.1"
|
||||
},
|
||||
|
@ -8198,8 +8438,7 @@
|
|||
"isarray": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
|
||||
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
|
||||
"dev": true
|
||||
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -9924,12 +10163,48 @@
|
|||
"prop-types": "^15.6.0"
|
||||
}
|
||||
},
|
||||
"react-emotion": {
|
||||
"version": "9.2.4",
|
||||
"resolved": "https://registry.npmjs.org/react-emotion/-/react-emotion-9.2.4.tgz",
|
||||
"integrity": "sha1-mOAPcM4spO4TkjRgEj52PkksATo=",
|
||||
"requires": {
|
||||
"babel-plugin-emotion": "^9.2.4",
|
||||
"create-emotion-styled": "^9.2.3"
|
||||
}
|
||||
},
|
||||
"react-error-overlay": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-4.0.0.tgz",
|
||||
"integrity": "sha512-FlsPxavEyMuR6TjVbSSywovXSEyOg6ZDj5+Z8nbsRl9EkOzAhEIcS+GLoQDC5fz/t9suhUXWmUrOBrgeUvrMxw==",
|
||||
"dev": true
|
||||
},
|
||||
"react-router": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-4.3.1.tgz",
|
||||
"integrity": "sha512-yrvL8AogDh2X42Dt9iknk4wF4V8bWREPirFfS9gLU1huk6qK41sg7Z/1S81jjTrGHxa3B8R3J6xIkDAA6CVarg==",
|
||||
"requires": {
|
||||
"history": "^4.7.2",
|
||||
"hoist-non-react-statics": "^2.5.0",
|
||||
"invariant": "^2.2.4",
|
||||
"loose-envify": "^1.3.1",
|
||||
"path-to-regexp": "^1.7.0",
|
||||
"prop-types": "^15.6.1",
|
||||
"warning": "^4.0.1"
|
||||
}
|
||||
},
|
||||
"react-router-dom": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-4.3.1.tgz",
|
||||
"integrity": "sha512-c/MlywfxDdCp7EnB7YfPMOfMD3tOtIjrQlj/CKfNMBxdmpJP8xcz5P/UAFn3JbnQCNUxsHyVVqllF9LhgVyFCA==",
|
||||
"requires": {
|
||||
"history": "^4.7.2",
|
||||
"invariant": "^2.2.4",
|
||||
"loose-envify": "^1.3.1",
|
||||
"prop-types": "^15.6.1",
|
||||
"react-router": "^4.3.1",
|
||||
"warning": "^4.0.1"
|
||||
}
|
||||
},
|
||||
"react-scripts": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-1.1.4.tgz",
|
||||
|
@ -10398,6 +10673,11 @@
|
|||
"integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=",
|
||||
"dev": true
|
||||
},
|
||||
"resolve-pathname": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-2.2.0.tgz",
|
||||
"integrity": "sha512-bAFz9ld18RzJfddgrO2e/0S2O81710++chRMUxHjXOYKF6jTAMrUNZrEZ1PvV0zlhfjidm08iRPdTLPno1FuRg=="
|
||||
},
|
||||
"resolve-url": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
|
||||
|
@ -11060,8 +11340,7 @@
|
|||
"sprintf-js": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
||||
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
|
||||
"dev": true
|
||||
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
|
||||
},
|
||||
"sshpk": {
|
||||
"version": "1.14.2",
|
||||
|
@ -11230,6 +11509,16 @@
|
|||
"schema-utils": "^0.3.0"
|
||||
}
|
||||
},
|
||||
"stylis": {
|
||||
"version": "3.5.1",
|
||||
"resolved": "https://registry.npmjs.org/stylis/-/stylis-3.5.1.tgz",
|
||||
"integrity": "sha512-yM4PyeHuwhIOUHNJxi1/Mbq8kVLv4AkyE7IYLP/LK0lIFcr3tRa2H1iZlBYKIxOlf+/jruBTe8DdKSyQX9w4OA=="
|
||||
},
|
||||
"stylis-rule-sheet": {
|
||||
"version": "0.0.10",
|
||||
"resolved": "https://registry.npmjs.org/stylis-rule-sheet/-/stylis-rule-sheet-0.0.10.tgz",
|
||||
"integrity": "sha512-nTbZoaqoBnmK+ptANthb10ZRZOGC+EmTLLUxeYIuHNkEKcmKgXX1XWKkUBT2Ac4es3NybooPe0SmvKdhKJZAuw=="
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "5.4.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz",
|
||||
|
@ -11503,6 +11792,14 @@
|
|||
"integrity": "sha1-LmhELZ9k7HILjMieZEOsbKqVACk=",
|
||||
"dev": true
|
||||
},
|
||||
"touch": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/touch/-/touch-1.0.0.tgz",
|
||||
"integrity": "sha1-RJy+LbrlqMgDjjDXH6D/RklHxN4=",
|
||||
"requires": {
|
||||
"nopt": "~1.0.10"
|
||||
}
|
||||
},
|
||||
"tough-cookie": {
|
||||
"version": "2.4.3",
|
||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
|
||||
|
@ -11936,6 +12233,11 @@
|
|||
"spdx-expression-parse": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"value-equal": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/value-equal/-/value-equal-0.4.0.tgz",
|
||||
"integrity": "sha512-x+cYdNnaA3CxvMaTX0INdTCN8m8aF2uY9BvEqmxuYp8bL09cs/kWVQPVGcA35fMktdOsP69IgU7wFj/61dJHEw=="
|
||||
},
|
||||
"vary": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||
|
@ -11977,6 +12279,14 @@
|
|||
"makeerror": "1.0.x"
|
||||
}
|
||||
},
|
||||
"warning": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/warning/-/warning-4.0.1.tgz",
|
||||
"integrity": "sha512-rAVtTNZw+cQPjvGp1ox0XC5Q2IBFyqoqh+QII4J/oguyu83Bax1apbo2eqB8bHRS+fqYUBagys6lqUoVwKSmXQ==",
|
||||
"requires": {
|
||||
"loose-envify": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"watch": {
|
||||
"version": "0.10.0",
|
||||
"resolved": "https://registry.npmjs.org/watch/-/watch-0.10.0.tgz",
|
||||
|
|
|
@ -3,9 +3,12 @@
|
|||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"emotion": "^9.2.4",
|
||||
"react": "^16.4.1",
|
||||
"react-copy-to-clipboard": "^5.0.1",
|
||||
"react-dom": "^16.4.1",
|
||||
"react-emotion": "^9.2.4",
|
||||
"react-router-dom": "^4.3.1",
|
||||
"semantic-ui-less": "^2.2.12",
|
||||
"semantic-ui-react": "^0.81.3"
|
||||
},
|
||||
|
|
|
@ -6,16 +6,19 @@ import { apiGet } from './api/api.js';
|
|||
import { Container, Segment, Message } from 'semantic-ui-react';
|
||||
import './App.css';
|
||||
|
||||
const PodInfoView = ({pod, namespace}) => (
|
||||
<Segment basic>
|
||||
<Message>
|
||||
<Message.Header>Kube-ArangoDB</Message.Header>
|
||||
<p>Running in Pod <b>{pod}</b> in namespace <b>{namespace}</b>.</p>
|
||||
</Message>
|
||||
</Segment>
|
||||
);
|
||||
|
||||
const OperatorsView = ({deployment, pod, namespace}) => (
|
||||
<Container>
|
||||
{deployment ? <DeploymentOperator /> : <NoOperator />}
|
||||
<Segment basic>
|
||||
<Message>
|
||||
<Message.Header>Kube-ArangoDB</Message.Header>
|
||||
<p>Running in Pod <b>{pod}</b> in namespace <b>{namespace}</b>.</p>
|
||||
</Message>
|
||||
</Segment>
|
||||
</Container>
|
||||
<div>
|
||||
{deployment ? <DeploymentOperator pod-info={<PodInfoView pod={pod} namespace={namespace}/>}/> : <NoOperator />}
|
||||
</div>
|
||||
);
|
||||
|
||||
const LoadingView = () => (
|
||||
|
|
|
@ -13,6 +13,7 @@ class NoOperator extends Component {
|
|||
<p className="App-intro">
|
||||
There are no operators available yet.
|
||||
</p>
|
||||
{this.props["pod-info"]}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
88
dashboard/src/deployment/DeploymentDetails.js
Normal file
88
dashboard/src/deployment/DeploymentDetails.js
Normal file
|
@ -0,0 +1,88 @@
|
|||
import React, { Component } from 'react';
|
||||
import { apiGet } from '../api/api.js';
|
||||
import { Accordion, Header, Icon, List, Segment } from 'semantic-ui-react';
|
||||
import Loading from '../util/Loading.js';
|
||||
//import CommandInstruction from '../util/CommandInstruction.js';
|
||||
|
||||
const MemberGroupsView = ({member_groups}) => (
|
||||
<div>
|
||||
{member_groups.map((item) => <MemberListComponent
|
||||
group={item.group}
|
||||
members={item.members}
|
||||
/>)}
|
||||
</div>
|
||||
);
|
||||
|
||||
const MemberListView = ({group, activeMemberID, onClick, members}) => (
|
||||
<Segment>
|
||||
<Header>{group}</Header>
|
||||
<List divided>
|
||||
{members.map((item) => <MemberView memberInfo={item} active={item.id === activeMemberID} onClick={onClick}/>)}
|
||||
</List>
|
||||
</Segment>
|
||||
);
|
||||
|
||||
const MemberView = ({memberInfo, active, onClick}) => (
|
||||
<List.Item>
|
||||
<Accordion>
|
||||
<Accordion.Title active={active} onClick={() => onClick(memberInfo.id)}>
|
||||
<Icon name='dropdown' /> {memberInfo.id}
|
||||
</Accordion.Title>
|
||||
<Accordion.Content active={active}>
|
||||
<div>Pod: {memberInfo.pod_name}</div>
|
||||
<div>PVC: {memberInfo.pvc_name}</div>
|
||||
<div>PV: {memberInfo.pv_name}</div>
|
||||
</Accordion.Content>
|
||||
</Accordion>
|
||||
</List.Item>
|
||||
);
|
||||
|
||||
class MemberListComponent extends Component {
|
||||
state = {};
|
||||
|
||||
onClick = (id) => {
|
||||
this.setState({activeMemberID:(this.state.activeMemberID === id) ? null : id});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (<MemberListView
|
||||
group={this.props.group}
|
||||
members={this.props.members}
|
||||
activeMemberID={this.state.activeMemberID}
|
||||
onClick={this.onClick}
|
||||
/>);
|
||||
}
|
||||
}
|
||||
|
||||
class DeploymentDetails extends Component {
|
||||
state = {};
|
||||
|
||||
componentDidMount() {
|
||||
this.intervalId = setInterval(this.reloadDeployment, 5000);
|
||||
this.reloadDeployment();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
clearInterval(this.intervalId);
|
||||
}
|
||||
|
||||
reloadDeployment = async() => {
|
||||
// TODO
|
||||
const result = await apiGet(`/api/deployment/${this.props.name}`);
|
||||
this.setState({deployment:result});
|
||||
}
|
||||
|
||||
render() {
|
||||
const d = this.state.deployment;
|
||||
if (!d) {
|
||||
return (<Loading/>);
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<MemberGroupsView member_groups={d.member_groups}/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default DeploymentDetails;
|
|
@ -3,6 +3,7 @@ import { apiGet } from '../api/api.js';
|
|||
import { Icon, Popup, Table } from 'semantic-ui-react';
|
||||
import Loading from '../util/Loading.js';
|
||||
import CommandInstruction from '../util/CommandInstruction.js';
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
const HeaderView = () => (
|
||||
<Table.Header>
|
||||
|
@ -33,23 +34,43 @@ const NoDatabaseLinkView = () => (
|
|||
</Popup>
|
||||
);
|
||||
|
||||
const RowView = ({name, mode, version, license, ready_pod_count, pod_count, ready_volume_count, volume_count, storage_classes, database_url, delete_command}) => (
|
||||
const RowView = ({name, mode, environment, version, license, ready_pod_count, pod_count, ready_volume_count, volume_count, storage_classes, database_url, delete_command}) => (
|
||||
<Table.Row>
|
||||
<Table.Cell><Icon name="bell" color="red"/></Table.Cell>
|
||||
<Table.Cell>{name}</Table.Cell>
|
||||
<Table.Cell>{mode}</Table.Cell>
|
||||
<Table.Cell>{version} {(license) ? `(${license})` : "" }</Table.Cell>
|
||||
<Table.Cell>
|
||||
<Icon name="bell" color="red"/>
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
<Link to={`/deployment/${name}`}>
|
||||
{name}
|
||||
</Link>
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
{mode}
|
||||
<span style={{"float":"right"}}>
|
||||
{(environment==="Development") ? <Popup trigger={<Icon name="laptop"/>} content="Development environment"/>: null}
|
||||
{(environment==="Production") ? <Popup trigger={<Icon name="warehouse"/>} content="Production environment"/>: null}
|
||||
</span>
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
{version}
|
||||
<span style={{"float":"right"}}>
|
||||
{(license==="community") ? <Popup trigger={<Icon name="users"/>} content="Community edition"/>: null}
|
||||
{(license==="enterprise") ? <Popup trigger={<Icon name="dollar"/>} content="Enterprise edition"/>: null}
|
||||
</span>
|
||||
</Table.Cell>
|
||||
<Table.Cell>{ready_pod_count} / {pod_count}</Table.Cell>
|
||||
<Table.Cell>{ready_volume_count} / {volume_count}</Table.Cell>
|
||||
<Table.Cell>{storage_classes.map((item) => (item === "") ? "<default>" : item)}</Table.Cell>
|
||||
<Table.Cell>
|
||||
{ database_url ? <DatabaseLinkView name={name} url={database_url}/> : <NoDatabaseLinkView/>}
|
||||
<CommandInstruction
|
||||
trigger={<Icon floated="right" name="trash alternate"/>}
|
||||
command={delete_command}
|
||||
title="Delete deployment"
|
||||
description="To delete this deployment, run:"
|
||||
/>
|
||||
<span style={{"float":"right"}}>
|
||||
<CommandInstruction
|
||||
trigger={<Icon link name="trash"/>}
|
||||
command={delete_command}
|
||||
title="Delete deployment"
|
||||
description="To delete this deployment, run:"
|
||||
/>
|
||||
</span>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
);
|
||||
|
@ -65,6 +86,7 @@ const ListView = ({items}) => (
|
|||
name={item.name}
|
||||
namespace={item.namespace}
|
||||
mode={item.mode}
|
||||
environment={item.environment}
|
||||
version={item.database_version}
|
||||
license={item.database_license}
|
||||
ready_pod_count={item.ready_pod_count}
|
||||
|
|
|
@ -1,18 +1,63 @@
|
|||
import React, { Component } from 'react';
|
||||
import DeploymentDetails from './DeploymentDetails.js';
|
||||
import DeploymentList from './DeploymentList.js';
|
||||
import { Header, Segment } from 'semantic-ui-react';
|
||||
//import logo from './logo.svg';
|
||||
//import './App.css';
|
||||
import { Header, Menu, Segment } from 'semantic-ui-react';
|
||||
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
|
||||
import styled from 'react-emotion';
|
||||
|
||||
const StyledMenu = styled(Menu)`
|
||||
width: 15rem !important;
|
||||
@media (max-width: 768px) {
|
||||
width: 10rem !important;
|
||||
}
|
||||
`;
|
||||
|
||||
const StyledContentBox = styled('div')`
|
||||
margin-left: 15rem;
|
||||
@media (max-width: 768px) {
|
||||
margin-left: 10rem;
|
||||
}
|
||||
`;
|
||||
|
||||
const ListView = () => (
|
||||
<div>
|
||||
<Header dividing>
|
||||
ArangoDeployments
|
||||
</Header>
|
||||
<DeploymentList/>
|
||||
</div>
|
||||
);
|
||||
|
||||
const DetailView = ({match}) => (
|
||||
<div>
|
||||
<Header dividing>
|
||||
ArangoDeployment {match.params.name}
|
||||
</Header>
|
||||
<DeploymentDetails name={match.params.name}/>
|
||||
</div>
|
||||
);
|
||||
|
||||
class DeploymentOperator extends Component {
|
||||
render() {
|
||||
return (
|
||||
<Segment basic>
|
||||
<Header dividing>
|
||||
ArangoDeployments....
|
||||
</Header>
|
||||
<DeploymentList/>
|
||||
</Segment>
|
||||
<Router>
|
||||
<div>
|
||||
<StyledMenu fixed="left" vertical>
|
||||
<Menu.Item>
|
||||
<Link to="/">Deployments</Link>
|
||||
</Menu.Item>
|
||||
</StyledMenu>
|
||||
<StyledContentBox>
|
||||
<Segment basic clearing>
|
||||
<div>
|
||||
<Route exact path="/" component={ListView} />
|
||||
<Route path="/deployment/:name" component={DetailView} />
|
||||
</div>
|
||||
</Segment>
|
||||
{this.props["pod-info"]}
|
||||
</StyledContentBox>
|
||||
</div>
|
||||
</Router>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,9 @@
|
|||
|
||||
package deployment
|
||||
|
||||
import "github.com/pkg/errors"
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
maskAny = errors.WithStack
|
||||
|
|
|
@ -32,6 +32,7 @@ import (
|
|||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1alpha"
|
||||
"github.com/arangodb/kube-arangodb/pkg/server"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
|
||||
)
|
||||
|
||||
|
@ -50,6 +51,11 @@ func (d *Deployment) Mode() api.DeploymentMode {
|
|||
return d.GetSpec().GetMode()
|
||||
}
|
||||
|
||||
// Environment returns the environment used in the deployment.
|
||||
func (d *Deployment) Environment() api.Environment {
|
||||
return d.GetSpec().GetEnvironment()
|
||||
}
|
||||
|
||||
// PodCount returns the number of pods for the deployment
|
||||
func (d *Deployment) PodCount() int {
|
||||
count := 0
|
||||
|
@ -192,3 +198,24 @@ func (d *Deployment) DatabaseVersion() (string, string) {
|
|||
}
|
||||
return string(info.ArangoDBVersion), license
|
||||
}
|
||||
|
||||
// Members returns all members of the deployment by role.
|
||||
func (d *Deployment) Members() map[api.ServerGroup][]server.Member {
|
||||
result := make(map[api.ServerGroup][]server.Member)
|
||||
status, _ := d.GetStatus()
|
||||
status.Members.ForeachServerGroup(func(group api.ServerGroup, list api.MemberStatusList) error {
|
||||
members := make([]server.Member, len(list))
|
||||
for i, m := range list {
|
||||
members[i] = member{
|
||||
d: d,
|
||||
id: m.ID,
|
||||
group: group,
|
||||
}
|
||||
}
|
||||
if len(members) > 0 {
|
||||
result[group] = members
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
|
68
pkg/deployment/server_member_api.go
Normal file
68
pkg/deployment/server_member_api.go
Normal file
|
@ -0,0 +1,68 @@
|
|||
//
|
||||
// DISCLAIMER
|
||||
//
|
||||
// Copyright 2018 ArangoDB GmbH, Cologne, Germany
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Copyright holder is ArangoDB GmbH, Cologne, Germany
|
||||
//
|
||||
// Author Ewout Prangsma
|
||||
//
|
||||
|
||||
package deployment
|
||||
|
||||
import (
|
||||
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1alpha"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
type member struct {
|
||||
d *Deployment
|
||||
group api.ServerGroup
|
||||
id string
|
||||
}
|
||||
|
||||
func (m member) status() (api.MemberStatus, bool) {
|
||||
status, _ := m.d.GetStatus()
|
||||
result, _, found := status.Members.ElementByID(m.id)
|
||||
return result, found
|
||||
}
|
||||
|
||||
func (m member) ID() string {
|
||||
return m.id
|
||||
}
|
||||
|
||||
func (m member) PodName() string {
|
||||
if status, found := m.status(); found {
|
||||
return status.PodName
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m member) PVCName() string {
|
||||
if status, found := m.status(); found {
|
||||
return status.PersistentVolumeClaimName
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m member) PVName() string {
|
||||
if status, found := m.status(); found && status.PersistentVolumeClaimName != "" {
|
||||
pvcs := m.d.deps.KubeCli.CoreV1().PersistentVolumeClaims(m.d.Namespace())
|
||||
if pvc, err := pvcs.Get(status.PersistentVolumeClaimName, metav1.GetOptions{}); err == nil {
|
||||
return pvc.Spec.VolumeName
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
|
@ -47,3 +47,16 @@ func (o *Operator) GetDeployments() ([]server.Deployment, error) {
|
|||
})
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// GetDeployment returns detailed information for a deployment, managed by the operator, with given name
|
||||
func (o *Operator) GetDeployment(name string) (server.Deployment, error) {
|
||||
o.Dependencies.LivenessProbe.Lock()
|
||||
defer o.Dependencies.LivenessProbe.Unlock()
|
||||
|
||||
for _, d := range o.deployments {
|
||||
if d.Name() == name {
|
||||
return d, nil
|
||||
}
|
||||
}
|
||||
return nil, maskAny(server.NotFoundError)
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
@ -30,13 +31,21 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
maskAny = errors.WithStack
|
||||
maskAny = errors.WithStack
|
||||
NotFoundError = fmt.Errorf("not found")
|
||||
)
|
||||
|
||||
func isNotFound(err error) bool {
|
||||
return err == NotFoundError || errors.Cause(err) == NotFoundError
|
||||
}
|
||||
|
||||
// sendError sends an error on the given context
|
||||
func sendError(c *gin.Context, err error) {
|
||||
// TODO proper status handling
|
||||
code := http.StatusInternalServerError
|
||||
if isNotFound(err) {
|
||||
code = http.StatusNotFound
|
||||
}
|
||||
c.JSON(code, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
|
|
|
@ -24,6 +24,8 @@ package server
|
|||
|
||||
import (
|
||||
"net/http"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
|
@ -35,6 +37,7 @@ type Deployment interface {
|
|||
Name() string
|
||||
Namespace() string
|
||||
Mode() api.DeploymentMode
|
||||
Environment() api.Environment
|
||||
PodCount() int
|
||||
ReadyPodCount() int
|
||||
VolumeCount() int
|
||||
|
@ -42,11 +45,23 @@ type Deployment interface {
|
|||
StorageClasses() []string
|
||||
DatabaseURL() string
|
||||
DatabaseVersion() (string, string)
|
||||
Members() map[api.ServerGroup][]Member
|
||||
}
|
||||
|
||||
// Member is the API implemented by a member of an ArangoDeployment.
|
||||
type Member interface {
|
||||
ID() string
|
||||
PodName() string
|
||||
PVCName() string
|
||||
PVName() string
|
||||
}
|
||||
|
||||
// DeploymentOperator is the API implemented by the deployment operator.
|
||||
type DeploymentOperator interface {
|
||||
// GetDeployments returns basic information for all deployments managed by the operator
|
||||
GetDeployments() ([]Deployment, error)
|
||||
// GetDeployment returns detailed information for a deployment, managed by the operator, with given name
|
||||
GetDeployment(name string) (Deployment, error)
|
||||
}
|
||||
|
||||
// DeploymentInfo is the information returned per deployment.
|
||||
|
@ -54,6 +69,7 @@ type DeploymentInfo struct {
|
|||
Name string `json:"name"`
|
||||
Namespace string `json:"namespace"`
|
||||
Mode api.DeploymentMode `json:"mode"`
|
||||
Environment api.Environment `json:"environment"`
|
||||
PodCount int `json:"pod_count"`
|
||||
ReadyPodCount int `json:"ready_pod_count"`
|
||||
VolumeCount int `json:"volume_count"`
|
||||
|
@ -64,6 +80,76 @@ type DeploymentInfo struct {
|
|||
DatabaseLicense string `json:"database_license"`
|
||||
}
|
||||
|
||||
// newDeploymentInfo initializes a DeploymentInfo for the given Deployment.
|
||||
func newDeploymentInfo(d Deployment) DeploymentInfo {
|
||||
version, license := d.DatabaseVersion()
|
||||
return DeploymentInfo{
|
||||
Name: d.Name(),
|
||||
Namespace: d.Namespace(),
|
||||
Mode: d.Mode(),
|
||||
Environment: d.Environment(),
|
||||
PodCount: d.PodCount(),
|
||||
ReadyPodCount: d.ReadyPodCount(),
|
||||
VolumeCount: d.VolumeCount(),
|
||||
ReadyVolumeCount: d.ReadyVolumeCount(),
|
||||
StorageClasses: d.StorageClasses(),
|
||||
DatabaseURL: d.DatabaseURL(),
|
||||
DatabaseVersion: version,
|
||||
DatabaseLicense: license,
|
||||
}
|
||||
}
|
||||
|
||||
// MemberInfo contains detailed info of a specific member of the deployment
|
||||
type MemberInfo struct {
|
||||
ID string `json:"id"`
|
||||
PodName string `json:"pod_name"`
|
||||
PVCName string `json:"pvc_name"`
|
||||
PVName string `json:"pv_name"`
|
||||
}
|
||||
|
||||
// newMemberInfo creates a MemberInfo for the given member
|
||||
func newMemberInfo(m Member) MemberInfo {
|
||||
return MemberInfo{
|
||||
ID: m.ID(),
|
||||
PodName: m.PodName(),
|
||||
PVCName: m.PVCName(),
|
||||
PVName: m.PVName(),
|
||||
}
|
||||
}
|
||||
|
||||
// MemberGroupInfo contained detailed info of a group (e.g. Agent) of members
|
||||
type MemberGroupInfo struct {
|
||||
Group string `json:"group"`
|
||||
Members []MemberInfo `json:"members"`
|
||||
}
|
||||
|
||||
// DeploymentInfoDetails is the detailed information returned per deployment.
|
||||
type DeploymentInfoDetails struct {
|
||||
DeploymentInfo
|
||||
MemberGroups []MemberGroupInfo `json:"member_groups"`
|
||||
}
|
||||
|
||||
// newDeploymentInfoDetails initializes a DeploymentInfoDetails for the given Deployment.
|
||||
func newDeploymentInfoDetails(d Deployment) DeploymentInfoDetails {
|
||||
result := DeploymentInfoDetails{
|
||||
DeploymentInfo: newDeploymentInfo(d),
|
||||
}
|
||||
for group, list := range d.Members() {
|
||||
memberInfos := make([]MemberInfo, len(list))
|
||||
for i, m := range list {
|
||||
memberInfos[i] = newMemberInfo(m)
|
||||
}
|
||||
result.MemberGroups = append(result.MemberGroups, MemberGroupInfo{
|
||||
Group: strings.Title(group.AsRole()),
|
||||
Members: memberInfos,
|
||||
})
|
||||
}
|
||||
sort.Slice(result.MemberGroups, func(i, j int) bool {
|
||||
return result.MemberGroups[i].Group < result.MemberGroups[j].Group
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
// Handle a GET /api/deployment request
|
||||
func (s *Server) handleGetDeployments(c *gin.Context) {
|
||||
if do := s.deps.Operators.DeploymentOperator(); do != nil {
|
||||
|
@ -74,20 +160,7 @@ func (s *Server) handleGetDeployments(c *gin.Context) {
|
|||
} else {
|
||||
result := make([]DeploymentInfo, len(depls))
|
||||
for i, d := range depls {
|
||||
version, license := d.DatabaseVersion()
|
||||
result[i] = DeploymentInfo{
|
||||
Name: d.Name(),
|
||||
Namespace: d.Namespace(),
|
||||
Mode: d.Mode(),
|
||||
PodCount: d.PodCount(),
|
||||
ReadyPodCount: d.ReadyPodCount(),
|
||||
VolumeCount: d.VolumeCount(),
|
||||
ReadyVolumeCount: d.ReadyVolumeCount(),
|
||||
StorageClasses: d.StorageClasses(),
|
||||
DatabaseURL: d.DatabaseURL(),
|
||||
DatabaseVersion: version,
|
||||
DatabaseLicense: license,
|
||||
}
|
||||
result[i] = newDeploymentInfo(d)
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"deployments": result,
|
||||
|
@ -95,3 +168,17 @@ func (s *Server) handleGetDeployments(c *gin.Context) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle a GET /api/deployment/:name request
|
||||
func (s *Server) handleGetDeploymentDetails(c *gin.Context) {
|
||||
if do := s.deps.Operators.DeploymentOperator(); do != nil {
|
||||
// Fetch deployments
|
||||
depl, err := do.GetDeployment(c.Params.ByName("name"))
|
||||
if err != nil {
|
||||
sendError(c, err)
|
||||
} else {
|
||||
result := newDeploymentInfoDetails(depl)
|
||||
c.JSON(http.StatusOK, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -146,6 +146,7 @@ func NewServer(cli corev1.CoreV1Interface, cfg Config, deps Dependencies) (*Serv
|
|||
|
||||
// Deployment operator
|
||||
api.GET("/deployment", s.handleGetDeployments)
|
||||
api.GET("/deployment/:name", s.handleGetDeploymentDetails)
|
||||
}
|
||||
// Dashboard
|
||||
r.GET("/", createAssetFileHandler(dashboard.Assets.Files["index.html"]))
|
||||
|
|
Loading…
Reference in a new issue