diff --git a/README.md b/README.md index 0d759ca..f7caddf 100644 --- a/README.md +++ b/README.md @@ -218,4 +218,3 @@ See [CONTRIBUTING](CONTRIBUTING.md#security-issue-notifications) for more inform This library is licensed under the MIT-0 License. See the [LICENSE](LICENSE.txt) file. - diff --git a/frontend/src/components/CompAuroraNode01.js b/frontend/src/components/CompAuroraNode01.js index f663845..358b6f8 100644 --- a/frontend/src/components/CompAuroraNode01.js +++ b/frontend/src/components/CompAuroraNode01.js @@ -103,6 +103,9 @@ const ComponentObject = memo(({ sessionId, clusterId, nodeStats }) => { { nodeStats.role === "R" && R } + { nodeStats.role === "-" && + - + }   onClickNode()}>{nodeStats.name} diff --git a/frontend/src/components/CompDocumentDBNode01.js b/frontend/src/components/CompDocumentDBNode01.js index 153432d..ce61636 100644 --- a/frontend/src/components/CompDocumentDBNode01.js +++ b/frontend/src/components/CompDocumentDBNode01.js @@ -104,6 +104,9 @@ const ComponentObject = memo(({ sessionId, clusterId, nodeStats }) => { { nodeStats.role === "R" && R } + { nodeStats.role === "-" && + - + }   onClickNode()}>{nodeStats.name} @@ -117,6 +120,7 @@ const ComponentObject = memo(({ sessionId, clusterId, nodeStats }) => { {nodeStats.az} + { nodeStats.role !== "-" && { fontColorValue={configuration.colors.fonts.metric100} chartColorLine={"#D69855"} /> + } + { nodeStats.role !== "-" && { fontSizeValue={"14px"} fontColorValue={configuration.colors.fonts.metric100} /> + } + { nodeStats.role !== "-" && { fontSizeValue={"14px"} fontColorValue={configuration.colors.fonts.metric100} /> + } + { nodeStats.role !== "-" && { fontSizeValue={"14px"} fontColorValue={configuration.colors.fonts.metric100} /> + } + { nodeStats.role !== "-" && { fontSizeValue={"14px"} fontColorValue={configuration.colors.fonts.metric100} /> + } + { nodeStats.role !== "-" && { fontSizeValue={"14px"} fontColorValue={configuration.colors.fonts.metric100} /> + } + { nodeStats.role !== "-" && { fontSizeValue={"14px"} fontColorValue={configuration.colors.fonts.metric100} /> + } + { nodeStats.role !== "-" && { fontSizeValue={"14px"} fontColorValue={configuration.colors.fonts.metric100} /> + } - { detailsVisible === true && + { (detailsVisible === true && nodeStats.role !== "-" ) && diff --git a/frontend/src/components/CompElasticNode01.js b/frontend/src/components/CompElasticNode01.js index cf649a7..f79f83e 100644 --- a/frontend/src/components/CompElasticNode01.js +++ b/frontend/src/components/CompElasticNode01.js @@ -31,10 +31,14 @@ const ComponentObject = memo(({ connectionId, clusterId, nodeId, instance, port, { node.role === "slave" && R } + { node.role === "-" && + - + }   onClickNode()}>{node.name} + { node.role !== "-" && + } + { node.role !== "-" && + } + { node.role !== "-" && + } + { node.role !== "-" && + } + { node.role !== "-" && + } + { node.role !== "-" && + } + { node.role !== "-" && + } + { node.role !== "-" && + } + { node.role !== "-" && + } + { node.role !== "-" && + } - { detailsVisible === true && + { (detailsVisible === true && node.role !== "-" ) && @@ -163,6 +186,16 @@ const ComponentObject = memo(({ connectionId, clusterId, nodeId, instance, port, > +
+ +

+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
+

diff --git a/frontend/src/pages/Sm-aurora-mysql-01.js b/frontend/src/pages/Sm-aurora-mysql-01.js index 558b925..21f9591 100644 --- a/frontend/src/pages/Sm-aurora-mysql-01.js +++ b/frontend/src/pages/Sm-aurora-mysql-01.js @@ -1,7 +1,6 @@ import { useState,useEffect,useRef } from 'react'; import Axios from 'axios'; import { configuration } from './Configs'; -import {classMetric} from '../components/Functions'; import { useSearchParams } from 'react-router-dom'; import CustomHeader from "../components/Header"; import AppLayout from "@awsui/components-react/app-layout"; @@ -10,19 +9,20 @@ import Tabs from "@awsui/components-react/tabs"; import ColumnLayout from "@awsui/components-react/column-layout"; import { SplitPanel } from '@awsui/components-react'; +import StatusIndicator from "@awsui/components-react/status-indicator"; +import Spinner from "@awsui/components-react/spinner"; + +import SpaceBetween from "@awsui/components-react/space-between"; import Pagination from "@awsui/components-react/pagination"; import Link from "@awsui/components-react/link"; import Header from "@awsui/components-react/header"; import Container from "@awsui/components-react/container"; import AuroraNode from '../components/CompAuroraNode01'; -import CompSparkline01 from '../components/ChartSparkline01'; import CompMetric01 from '../components/Metric01'; -import CompMetric04 from '../components/Metric04'; import ChartLine02 from '../components/ChartLine02'; import CLWChart from '../components/ChartCLW03'; import ChartRadialBar01 from '../components/ChartRadialBar01'; -import ChartBar01 from '../components/ChartBar01'; import ChartColumn01 from '../components/ChartColumn01'; export const splitPanelI18nStrings: SplitPanelProps.I18nStrings = { @@ -63,7 +63,6 @@ function App() { const cnf_connection_id=parameter_object_values["session_id"]; const cnf_identifier=parameter_object_values["rds_id"]; const cnf_engine=parameter_object_values["rds_engine"]; - const cnf_engine_class=parameter_object_values["rds_class"]; const cnf_az=parameter_object_values["rds_az"]; const cnf_version=parameter_object_values["rds_version"]; const cnf_resource_id=parameter_object_values["rds_resource_id"]; @@ -85,94 +84,8 @@ function App() { //--######## RealTime Metric Features //-- Variable for Split Panels - const historyChartDetails = 20; const [splitPanelShow,setsplitPanelShow] = useState(false); - - - const [selectedItems,setSelectedItems] = useState([{ identifier: "" }]); - - const metricObjectGlobal = useRef(new classMetric([ - {name : "cpu", history : historyChartDetails }, - {name : "memory", history : historyChartDetails }, - {name : "ioreads", history : historyChartDetails }, - {name : "iowrites", history : historyChartDetails }, - {name : "netin", history : historyChartDetails }, - {name : "netout", history : historyChartDetails }, - {name : "queries", history : historyChartDetails }, - {name : "questions", history : historyChartDetails }, - {name : "comSelect", history : historyChartDetails }, - {name : "comInsert", history : historyChartDetails }, - {name : "comDelete", history : historyChartDetails }, - {name : "comUpdate", history : historyChartDetails }, - {name : "comCommit", history : historyChartDetails }, - {name : "comRollback", history : historyChartDetails }, - {name : "threads", history : historyChartDetails }, - {name : "threadsRunning", history : historyChartDetails }, - - ])); - - - var nodeMetrics = useRef([]); - var nodeMembers = useRef([]); const [metricDetailsIndex,setMetricDetailsIndex] = useState({index : 'cpu', title : 'CPU Usage(%)', timestamp : 0 }); - const [dataMetrics,setDataMetrics] = useState({ - cpu: 0, - memory: 0, - ioreads: 0, - iowrites: 0, - iops : 0, - netin: 0, - netout: 0, - network : 0, - queries: 0, - questions: 0, - comSelect: 0, - comInsert: 0, - comDelete: 0, - comUpdate: 0, - comCommit: 0, - comRollback: 0, - threads : 0, - threadsRunning : 0, - timestamp : 0, - refObject : new classMetric([ - {name : "cpu", history : historyChartDetails }, - {name : "memory", history : historyChartDetails }, - {name : "ioreads", history : historyChartDetails }, - {name : "iowrites", history : historyChartDetails }, - {name : "netin", history : historyChartDetails }, - {name : "netout", history : historyChartDetails }, - {name : "queries", history : historyChartDetails }, - {name : "questions", history : historyChartDetails }, - {name : "comSelect", history : historyChartDetails }, - {name : "comInsert", history : historyChartDetails }, - {name : "comDelete", history : historyChartDetails }, - {name : "comUpdate", history : historyChartDetails }, - {name : "comCommit", history : historyChartDetails }, - {name : "comRollback", history : historyChartDetails }, - {name : "threads", history : historyChartDetails }, - {name : "threadsRunning", history : historyChartDetails }, - ]), - metricDetails : [] - - }); - const [dataNodes,setDataNodes] = useState({ - MemberClusters : [], - ConfigurationEndpoint : "", - Port : "", - CacheNodeType : "", - ReplicationGroupId : "", - Status : "", - Version : "", - Shards : "", - ConfigurationUid : "", - ClusterEnabled : "", - MultiAZ : "", - DataTiering : "", - clwDimensions : "", - }); - - ////----- //-- Variable for Paging const [currentPageIndex,setCurrentPageIndex] = useState(1); @@ -184,6 +97,8 @@ function App() { const nodeList = useRef(""); const [clusterStats,setClusterStats] = useState({ cluster : { + status: "pending", + nodes : 0, cpu: 0, memory: 0, ioreads: 0, @@ -497,9 +412,23 @@ function App() { <>
- + + +
- {parameter_object_values['rds_host']} + + + { clusterStats['cluster']['status'] != 'available' && + + } + {parameter_object_values['rds_host']} + + {clusterStats['cluster']['status']} + Status + +
{clusterStats['cluster']['nodes']}
+ Nodes +
diff --git a/frontend/src/pages/Sm-aurora-postgresql-01.js b/frontend/src/pages/Sm-aurora-postgresql-01.js index 2fe8f82..6adf7ba 100644 --- a/frontend/src/pages/Sm-aurora-postgresql-01.js +++ b/frontend/src/pages/Sm-aurora-postgresql-01.js @@ -9,6 +9,10 @@ import Tabs from "@awsui/components-react/tabs"; import ColumnLayout from "@awsui/components-react/column-layout"; import { SplitPanel } from '@awsui/components-react'; +import StatusIndicator from "@awsui/components-react/status-indicator"; +import Spinner from "@awsui/components-react/spinner"; + +import SpaceBetween from "@awsui/components-react/space-between"; import Pagination from "@awsui/components-react/pagination"; import Link from "@awsui/components-react/link"; @@ -402,9 +406,23 @@ function App() { <> - + + +
- {parameter_object_values['rds_host']} + + + { clusterStats['cluster']['status'] != 'available' && + + } + {parameter_object_values['rds_host']} + + + {clusterStats['cluster']['status']} + Status +
{clusterStats['cluster']['nodes']}
+ Nodes +
diff --git a/frontend/src/pages/Sm-documentdb-01.js b/frontend/src/pages/Sm-documentdb-01.js index 1092ae4..7431e35 100644 --- a/frontend/src/pages/Sm-documentdb-01.js +++ b/frontend/src/pages/Sm-documentdb-01.js @@ -9,6 +9,10 @@ import ColumnLayout from "@awsui/components-react/column-layout"; import { SplitPanel } from '@awsui/components-react'; import AppLayout from "@awsui/components-react/app-layout"; +import Icon from "@awsui/components-react/icon"; +import StatusIndicator from "@awsui/components-react/status-indicator"; +import Spinner from "@awsui/components-react/spinner"; + import SpaceBetween from "@awsui/components-react/space-between"; import Pagination from "@awsui/components-react/pagination"; import Link from "@awsui/components-react/link"; @@ -101,6 +105,10 @@ function App() { const nodeList = useRef(""); const [clusterStats,setClusterStats] = useState({ cluster : { + status : "pending", + size : "-", + shards : 0, + nodes : 0, cpu: 0, memory: 0, ioreads: 0, @@ -419,9 +427,23 @@ function App() { <> - + + +
- {parameter_object_values['rds_host']} + + + { clusterStats['cluster']['status'] != 'available' && + + } + {parameter_object_values['rds_host']} + + + {clusterStats['cluster']['status']} + Status +
{clusterStats['cluster']['nodes']}
+ Nodes +
diff --git a/frontend/src/pages/Sm-elasticache-01.js b/frontend/src/pages/Sm-elasticache-01.js index 9cf741f..f8e420c 100644 --- a/frontend/src/pages/Sm-elasticache-01.js +++ b/frontend/src/pages/Sm-elasticache-01.js @@ -9,6 +9,11 @@ import Tabs from "@awsui/components-react/tabs"; import ColumnLayout from "@awsui/components-react/column-layout"; import { SplitPanel } from '@awsui/components-react'; +import Icon from "@awsui/components-react/icon"; +import StatusIndicator from "@awsui/components-react/status-indicator"; +import Spinner from "@awsui/components-react/spinner"; + +import SpaceBetween from "@awsui/components-react/space-between"; import Pagination from "@awsui/components-react/pagination"; import Link from "@awsui/components-react/link"; import Header from "@awsui/components-react/header"; @@ -87,6 +92,10 @@ function App() { const nodeList = useRef(""); const [clusterStats,setClusterStats] = useState({ cluster : { + status : "pending", + size : "-", + shards : 0, + nodes : 0, cpu: 0, memory: 0, memoryUsed: 0, @@ -154,7 +163,7 @@ function App() { var api_url = configuration["apps-settings"]["api_url"]; Axios.get(`${api_url}/api/redis/cluster/stats/update`,{ - params: { connectionId : cnf_connection_id, clusterId : cnf_identifier } + params: { connectionId : cnf_connection_id, clusterId : cnf_identifier, clusterType : "elasticache" } }).then((data)=>{ @@ -384,9 +393,31 @@ function App() { <> - + + + + +
- {parameter_object_values['rds_host']} + + + { clusterStats['cluster']['status'] != 'available' && + + } + {parameter_object_values['rds_host']} + + + {clusterStats['cluster']['status']} + Status +
{clusterStats['cluster']['shards']}
+ Shards +
+
{clusterStats['cluster']['nodes']}
+ Nodes +
+
{clusterStats['cluster']['size']}
+ NodeType +
@@ -478,20 +509,12 @@ function App() { clusterStats['cluster']['history']['operations'] ])} title={"Operations/sec"} height="180px" /> - {/* - - */} -


@@ -503,6 +526,7 @@ function App() { precision={0} format={1} fontColorValue={configuration.colors.fonts.metric100} + fontSizeValue={"18px"} />
@@ -512,68 +536,162 @@ function App() { precision={0} format={1} fontColorValue={configuration.colors.fonts.metric100} + fontSizeValue={"18px"} /> + value={clusterStats['cluster']['cmdExec'] || 0} + title={"execCalls/sec"} + precision={0} + format={1} + fontColorValue={configuration.colors.fonts.metric100} + fontSizeValue={"18px"} + /> + value={clusterStats['cluster']['cmdXadd'] || 0} + title={"xaddCalls/sec"} + precision={0} + format={1} + fontColorValue={configuration.colors.fonts.metric100} + fontSizeValue={"18px"} + />
-
+
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
+

@@ -1147,7 +1265,7 @@ function App() {
CacheNodeType -
{parameter_object_values['rds_size']}
+
{clusterStats['cluster']['size']}
ConfigurationEndpoint @@ -1163,7 +1281,7 @@ function App() {
Status -
{parameter_object_values['rds_status']}
+
{clusterStats['cluster']['status']}
ClusterEnabled @@ -1171,11 +1289,11 @@ function App() {
Shards -
{parameter_object_values['rds_shards']}
+
{clusterStats['cluster']['shards']}
Nodes -
{parameter_object_values['rds_nodes']}
+
{clusterStats['cluster']['nodes']}

diff --git a/frontend/src/pages/Sm-memorydb-01.js b/frontend/src/pages/Sm-memorydb-01.js index ae62af8..8fca8e0 100644 --- a/frontend/src/pages/Sm-memorydb-01.js +++ b/frontend/src/pages/Sm-memorydb-01.js @@ -9,6 +9,11 @@ import ColumnLayout from "@awsui/components-react/column-layout"; import { SplitPanel } from '@awsui/components-react'; import AppLayout from "@awsui/components-react/app-layout"; +import Icon from "@awsui/components-react/icon"; +import StatusIndicator from "@awsui/components-react/status-indicator"; +import Spinner from "@awsui/components-react/spinner"; + +import SpaceBetween from "@awsui/components-react/space-between"; import Pagination from "@awsui/components-react/pagination"; import Link from "@awsui/components-react/link"; import Header from "@awsui/components-react/header"; @@ -87,6 +92,10 @@ function App() { const nodeList = useRef(""); const [clusterStats,setClusterStats] = useState({ cluster : { + status : "pending", + size : "-", + shards : 0, + nodes : 0, cpu: 0, memory: 0, memoryUsed: 0, @@ -154,7 +163,7 @@ function App() { var api_url = configuration["apps-settings"]["api_url"]; Axios.get(`${api_url}/api/redis/cluster/stats/update`,{ - params: { connectionId : cnf_connection_id, clusterId : cnf_identifier } + params: { connectionId : cnf_connection_id, clusterId : cnf_identifier, clusterType : "memorydb" } }).then((data)=>{ @@ -181,7 +190,7 @@ function App() { Axios.get(`${api_url}/api/redis/cluster/stats/gather`,{ params: { connectionId : cnf_connection_id, clusterId : cnf_identifier, beginItem : ( (pageId.current-1) * itemsPerPage), endItem : (( (pageId.current-1) * itemsPerPage) + itemsPerPage) } }).then((data)=>{ - + console.log(data.data); setClusterStats({ cluster : data.data.cluster, nodes : data.data.nodes, @@ -384,9 +393,31 @@ function App() { <>
- + + + + +
- {parameter_object_values['rds_host']} + + + { clusterStats['cluster']['status'] != 'available' && + + } + {parameter_object_values['rds_host']} + + + {clusterStats['cluster']['status']} + Status + +
{clusterStats['cluster']['shards']}
+ Shards +
+
{clusterStats['cluster']['nodes']}
+ Nodes +
+
{clusterStats['cluster']['size']}
+ NodeType
@@ -409,8 +440,7 @@ function App() { @@ -467,7 +497,7 @@ function App() { height="180px" title={"Network (%)"} /> - + - {/* - - */} -


-
+ @@ -513,68 +536,162 @@ function App() { precision={0} format={1} fontColorValue={configuration.colors.fonts.metric100} + fontSizeValue={"18px"} /> + value={clusterStats['cluster']['cmdExec'] || 0} + title={"execCalls/sec"} + precision={0} + format={1} + fontColorValue={configuration.colors.fonts.metric100} + fontSizeValue={"18px"} + /> + value={clusterStats['cluster']['cmdXadd'] || 0} + title={"xaddCalls/sec"} + precision={0} + format={1} + fontColorValue={configuration.colors.fonts.metric100} + fontSizeValue={"18px"} + />
-
+
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + +
+

@@ -1137,7 +1254,7 @@ function App() {
CacheNodeType -
{parameter_object_values['rds_size']}
+
{clusterStats['cluster']['size']}
ConfigurationEndpoint @@ -1153,7 +1270,7 @@ function App() {
Status -
{parameter_object_values['rds_status']}
+
{clusterStats['cluster']['status']}
ACLName @@ -1161,11 +1278,11 @@ function App() {
Shards -
{parameter_object_values['rds_shards']}
+
{clusterStats['cluster']['shards']}
Nodes -
{parameter_object_values['rds_nodes']}
+
{clusterStats['cluster']['nodes']}

diff --git a/images/.gitignore b/images/.gitignore deleted file mode 100644 index 6c321fb..0000000 --- a/images/.gitignore +++ /dev/null @@ -1,161 +0,0 @@ -frontend/public/aws-exports.json -server/aws-exports.json - -# General -.DS_Store -.AppleDouble -.LSOverride - -# Icon must end with two \r -Icon - - -# Thumbnails -._* - -# Files that might appear in the root of a volume -.DocumentRevisions-V100 -.fseventsd -.Spotlight-V100 -.TemporaryItems -.Trashes -.VolumeIcon.icns -.com.apple.timemachine.donotpresent - -# Directories potentially created on remote AFP share -.AppleDB -.AppleDesktop -Network Trash Folder -Temporary Items -.apdisk - -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -lerna-debug.log* -.pnpm-debug.log* - -# Diagnostic reports (https://nodejs.org/api/report.html) -report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage -*.lcov - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ - -# Snowpack dependency directory (https://snowpack.dev/) -web_modules/ - -# TypeScript cache -*.tsbuildinfo - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Optional stylelint cache -.stylelintcache - -# Microbundle cache -.rpt2_cache/ -.rts2_cache_cjs/ -.rts2_cache_es/ -.rts2_cache_umd/ - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variable files -.env -.env.development.local -.env.test.local -.env.production.local -.env.local - -# parcel-bundler cache (https://parceljs.org/) -.cache -.parcel-cache - -# Next.js build output -.next -out - -# Nuxt.js build / generate output -.nuxt -dist - -# Gatsby files -.cache/ -# Comment in the public line in if your project uses Gatsby and not Next.js -# https://nextjs.org/blog/next-9-1#public-directory-support -# public - -# vuepress build output -.vuepress/dist - -# vuepress v2.x temp and cache directory -.temp -.cache - -# Docusaurus cache and generated files -.docusaurus - -# Serverless directories -.serverless/ - -# FuseBox cache -.fusebox/ - -# DynamoDB Local files -.dynamodb/ - -# TernJS port file -.tern-port - -# Stores VSCode versions used for testing VSCode extensions -.vscode-test - -# yarn v2 -.yarn/cache -.yarn/unplugged -.yarn/build-state.yml -.yarn/install-state.gz -.pnp.* diff --git a/images/image07.png b/images/image07.png deleted file mode 100644 index 5528e68..0000000 Binary files a/images/image07.png and /dev/null differ diff --git a/images/image08.png b/images/image08.png deleted file mode 100644 index 6fc06b0..0000000 Binary files a/images/image08.png and /dev/null differ diff --git a/server/api.core.js b/server/api.core.js index f2d6a56..dfca420 100644 --- a/server/api.core.js +++ b/server/api.core.js @@ -97,31 +97,6 @@ var memorydb = new AWS.MemoryDB(); var dbRedis = {}; var dbRedisCluster = {}; -var nodeType = { - name : "", - cpuUser: 0, - cpuSys: 0, - memory: 0, - memoryUsed: 0, - memoryTotal: 0, - operations: 0, - getCalls: 0, - getUsec: 0, - setCalls: 0, - setUsec: 0, - connectedClients: 0, - getLatency: 0, - setLatency: 0, - keyspaceHits: 0, - keyspaceMisses: 0, - netIn: 0, - netOut: 0, - connectionsTotal: 0, - commands: 0, - timestamp : 0 - -}; - // DocumentDB Variables @@ -449,7 +424,7 @@ app.post("/api/security/rds/auth/", csrfProtection, (req,res)=>{ ] ) ; auroraCluster["$" + session_id][ "$" + params.cluster]["property"] = function(){}; - auroraCluster["$" + session_id][ "$" + params.cluster]["property"] = { clusterId: params.cluster, timestamp : "" } + auroraCluster["$" + session_id][ "$" + params.cluster]["property"] = { clusterId: params.cluster, timestamp : "", status : "pending", nodes: 0, instanceRoles : [] } } @@ -476,6 +451,12 @@ app.post("/api/security/rds/auth/", csrfProtection, (req,res)=>{ port: params.port, max: 1, }) + + dbconnection.on('error', (err, client) => { + console.log('Unexpected error on idle PostgreSQL client initial.'); + console.log(err); + }); + dbconnection.connect(function(err) { if (err) { res.status(200).send( {"result":"auth0", "session_id": 0}); @@ -512,7 +493,7 @@ app.post("/api/security/rds/auth/", csrfProtection, (req,res)=>{ ] ) ; auroraCluster["$" + session_id][ "$" + params.cluster]["property"] = function(){}; - auroraCluster["$" + session_id][ "$" + params.cluster]["property"] = { clusterId: params.cluster, timestamp : "" } + auroraCluster["$" + session_id][ "$" + params.cluster]["property"] = { clusterId: params.cluster, timestamp : "", status : "pending", nodes: 0, instanceRoles : [] } @@ -624,9 +605,7 @@ app.get("/api/security/rds/disconnect/", (req,res)=>{ if (standardToken.isValid === false || cognitoToken.isValid === false) return res.status(511).send({ data: [], message : "Token is invalid. StandardToken : " + String(standardToken.isValid) + ", CognitoToken : " + String(cognitoToken.isValid) }); - // API Call - try { switch(req.query.engine) @@ -856,6 +835,7 @@ async function openAuroraPostgresqlConnectionCluster(req, res) { roleType[instance['DBInstanceIdentifier']] = ( String(instance['IsClusterWriter']) == "true" ? "P" : "R" ); }); + auroraCluster["$" + params.connectionId]["$" + params.clusterId]["property"]["instanceRoles"] = roleType; // Gather Instances var parameter = { @@ -950,9 +930,14 @@ async function openAuroraPostgresqlConnectionNode(node){ password: node.password, database: "postgres", port: node.port, - max: 2, + //max: 1, }); + auroraCluster[connectionId][clusterId][instanceId]["connection"].on('error', (err) => { + console.log('Unexpected error on idle PostgreSQL client.'); + console.log(err); + }); + auroraCluster[connectionId][clusterId][instanceId]["node"] = function(){}; auroraCluster[connectionId][clusterId][instanceId]["node"] = new classMetric( node.nodeUid, @@ -1022,6 +1007,8 @@ async function updateStatsAuroraClusterPostgresql(req, res) { { var params = req.query; + updateStatusAuoraCluster(params.connectionId, params.clusterId); + var nodes = auroraCluster["$" + params.connectionId]["$" + params.clusterId]; for (let nodeId of Object.keys(nodes)) { if (nodeId != "cluster" && nodeId != "property" ){ @@ -1352,7 +1339,7 @@ async function gatherStatsAuroraClusterPostgresql(req, res) { var nodeStats = { name : auroraCluster[connectionId][clusterId][nodeId]["property"]["instanceId"], monitoring : auroraCluster[connectionId][clusterId][nodeId]["property"]["monitoring"], - role : auroraCluster[connectionId][clusterId][nodeId]["property"]["role"], + role : auroraCluster[connectionId][clusterId]["property"]["instanceRoles"][auroraCluster[connectionId][clusterId][nodeId]["property"]["instanceId"]], size : auroraCluster[connectionId][clusterId][nodeId]["property"]["size"], az : auroraCluster[connectionId][clusterId][nodeId]["property"]["az"], status : auroraCluster[connectionId][clusterId][nodeId]["property"]["status"], @@ -1463,6 +1450,8 @@ async function gatherStatsAuroraClusterPostgresql(req, res) { res.status(200).send( { cluster : { + status : auroraCluster[connectionId][clusterId]["property"]["status"], + nodes : auroraCluster[connectionId][clusterId]["property"]["nodes"], ...clusterInfo, history : { cpu: auroraCluster[connectionId][clusterId]["cluster"].getPropertyValues('cpu'), @@ -1672,6 +1661,7 @@ async function openAuroraMysqlConnectionCluster(req, res) { roleType[instance['DBInstanceIdentifier']] = ( String(instance['IsClusterWriter']) == "true" ? "P" : "R" ); }); + auroraCluster["$" + params.connectionId]["$" + params.clusterId]["property"]["instanceRoles"] = roleType; // Gather Instances var parameter = { @@ -1862,6 +1852,8 @@ async function updateStatsAuroraClusterMysql(req, res) { { var params = req.query; + updateStatusAuoraCluster(params.connectionId, params.clusterId); + var nodes = auroraCluster["$" + params.connectionId]["$" + params.clusterId]; for (let nodeId of Object.keys(nodes)) { if (nodeId != "cluster" && nodeId != "property" ){ @@ -1880,11 +1872,67 @@ async function updateStatsAuroraClusterMysql(req, res) { } +async function updateStatusAuoraCluster(connectionId,clusterId) { + + + try { + + var parameterCluster = { + DBClusterIdentifier: clusterId, + MaxRecords: 100 + }; + + var clusterData = await rds.describeDBClusters(parameterCluster).promise(); + + auroraCluster["$" + connectionId]["$" + clusterId]["property"]["status"] = clusterData['DBClusters'][0]['Status']; + auroraCluster["$" + connectionId]["$" + clusterId]["property"]["nodes"] =clusterData['DBClusters'][0]['DBClusterMembers'].length; + + + var roleType = []; + + clusterData['DBClusters'][0]['DBClusterMembers'].forEach(function(instance) { + roleType[instance['DBInstanceIdentifier']] = ( String(instance['IsClusterWriter']) == "true" ? "P" : "R" ); + }); + + auroraCluster["$" + connectionId]["$" + clusterId]["property"]["instanceRoles"] = roleType; + + + } + catch(err){ + try { + auroraCluster["$" + connectionId]["$" + clusterId]["property"]["status"] = "pending"; + auroraCluster["$" + connectionId]["$" + clusterId]["property"]["nodes"] = 0; + } + catch(err){ + console.log(err); + } + + } + + + +} + async function updateStatsAuoraMysqlNode(connectionId,clusterId,nodeId, resourceId, monitoring) { + var instanceInfo = { status : "-", size : "" }; + try { var timeNow = new Date(); + + // Current Instance Status + var parameter = { + DBInstanceIdentifier : nodeId.substring(1) + }; + + var instanceData = await rds.describeDBInstances(parameter).promise(); + + if (instanceData.DBInstances.length > 0) { + instanceInfo.status = instanceData.DBInstances[0]['DBInstanceStatus']; + instanceInfo.size = instanceData.DBInstances[0]['DBInstanceClass']; + } + var sql_statement = "SHOW GLOBAL STATUS"; var currentOperations = await auroraCluster[connectionId][clusterId][nodeId]["connectionPromise"].query(sql_statement); @@ -1922,13 +1970,18 @@ async function updateStatsAuoraMysqlNode(connectionId,clusterId,nodeId, resource timeNow.getTime()); auroraCluster[connectionId][clusterId][nodeId]["property"]["timestamp"] = osMetrics.timestamp; + auroraCluster[connectionId][clusterId][nodeId]["property"]["status"] = instanceInfo.status; + auroraCluster[connectionId][clusterId][nodeId]["property"]["size"] = instanceInfo.size; } catch(err){ - console.log(err); + + auroraCluster[connectionId][clusterId][nodeId]["property"]["status"] = instanceInfo.status; + auroraCluster[connectionId][clusterId][nodeId]["property"]["size"] = instanceInfo.size; + console.log(err); } } @@ -1999,7 +2052,7 @@ async function gatherStatsAuroraClusterMysql(req, res) { var nodeStats = { name : auroraCluster[connectionId][clusterId][nodeId]["property"]["instanceId"], monitoring : auroraCluster[connectionId][clusterId][nodeId]["property"]["monitoring"], - role : auroraCluster[connectionId][clusterId][nodeId]["property"]["role"], + role : auroraCluster[connectionId][clusterId]["property"]["instanceRoles"][auroraCluster[connectionId][clusterId][nodeId]["property"]["instanceId"]], size : auroraCluster[connectionId][clusterId][nodeId]["property"]["size"], az : auroraCluster[connectionId][clusterId][nodeId]["property"]["az"], status : auroraCluster[connectionId][clusterId][nodeId]["property"]["status"], @@ -2109,6 +2162,8 @@ async function gatherStatsAuroraClusterMysql(req, res) { res.status(200).send( { cluster : { + status : auroraCluster[connectionId][clusterId]["property"]["status"], + nodes : auroraCluster[connectionId][clusterId]["property"]["nodes"], ...clusterInfo, history : { cpu: auroraCluster[connectionId][clusterId]["cluster"].getPropertyValues('cpu'), @@ -2368,6 +2423,10 @@ async function authRedisConnection(req, res) { {name : "keyspaceMisses", history : 20 } ] ) ; + + dbRedisCluster["$" + session_id][ "$" + params.cluster]["property"] = function(){}; + dbRedisCluster["$" + session_id][ "$" + params.cluster]["property"] = { status : "pending", size : "-", shards : 0 , nodes : 0}; + dbconnection.quit(); res.status(200).send( {"result":"auth1", "session_id": session_id, "session_token": token }); @@ -2522,21 +2581,24 @@ async function openRedisMemoryDBConnectionCluster(req, res) { rg['Shards'].forEach(function(shard) { shard['Nodes'].forEach(function(node) { - - openRedisConnectionNode({ - connectionId : params.connectionId, - clusterId: params.clusterId, - username: params.username, - password: params.password, - auth: params.auth, - ssl : params.ssl, - nodeId : node['Name'], - endPoint : node['Endpoint']['Address'], - port : nodePort, - nodeUid : nodeUid, - nodeType : rg['NodeType'] - }); - + try { + openRedisConnectionNode({ + connectionId : params.connectionId, + clusterId: params.clusterId, + username: params.username, + password: params.password, + auth: params.auth, + ssl : params.ssl, + nodeId : node['Name'], + endPoint : node['Endpoint']['Address'], + port : nodePort, + nodeUid : nodeUid, + nodeType : rg['NodeType'] + }); + } + catch(err){ + console.log(err); + } nodeUid ++; nodeList = nodeList + ( rg['Name'] + "|" + node['Name'] ) + "," @@ -2655,10 +2717,40 @@ async function openRedisConnectionNode(node){ } dbRedisCluster[connectionId][clusterId][instanceId]["property"] = function(){}; - dbRedisCluster[connectionId][clusterId][instanceId]["property"] = { nodeType : node.nodeType, nodeNetworkRate : nodeNetworkRate}; + dbRedisCluster[connectionId][clusterId][instanceId]["property"] = { nodeType : node.nodeType, nodeNetworkRate : nodeNetworkRate, role : ""}; - dbRedisCluster[connectionId][clusterId][instanceId]["node"].newSnapshot(nodeType,timeNow.getTime()); + dbRedisCluster[connectionId][clusterId][instanceId]["node"].newSnapshot({ + name : "", + cpuUser: 0, + cpuSys: 0, + memory: 0, + memoryUsed: 0, + memoryTotal: 0, + operations: 0, + getCalls: 0, + getUsec: 0, + setCalls: 0, + setUsec: 0, + connectedClients: 0, + getLatency: 0, + setLatency: 0, + keyspaceHits: 0, + keyspaceMisses: 0, + netIn: 0, + netOut: 0, + connectionsTotal: 0, + commands: 0, + cmdExec: 0, + cmdAuth: 0, + cmdInfo: 0, + cmdScan: 0, + cmdXadd: 0, + cmdZadd: 0, + keys : 0, + timestamp : 0 + },timeNow.getTime()); + dbRedisCluster[connectionId][clusterId][instanceId]["connection"].on('error', err => { console.log(err.message); }); @@ -2667,10 +2759,10 @@ async function openRedisConnectionNode(node){ .then(()=> { console.log("Redis Instance Connected : " + node.connectionId + " # " + node.clusterId + " # " + node.nodeId ); - }) - .catch(()=> { + .catch((err)=> { console.log("Redis Instance Connected with Errors : " + node.connectionId + " # " + node.clusterId + " # " + node.nodeId ); + console.log(err); }); @@ -2678,6 +2770,22 @@ async function openRedisConnectionNode(node){ else { console.log("Re-using - Redis Instance connection : " + node.connectionId + " # " + node.clusterId + " # " + node.nodeId ); + try { + + dbRedisCluster[connectionId][clusterId][instanceId]["connection"].connect() + .then(()=> { + console.log("Redis Instance Re-Connected after fail connection : " + node.connectionId + " # " + node.clusterId + " # " + node.nodeId ); + }) + .catch((err)=> { + console.log("Redis Instance Re-Connected after fail connection with Errors : " + node.connectionId + " # " + node.clusterId + " # " + node.nodeId ); + console.log(err); + }); + + } + catch(err){ + console.log(err); + } + } @@ -2701,6 +2809,7 @@ async function updateStatsRedisCluster(req, res) { var params = req.query; updateStatsRedisClusterCommand(params.connectionId, params.clusterId); + updateStatusRedisCluster(params.connectionId, params.clusterId, params.clusterType); res.status(200).send( {"result":"Cluster Update Stats Requested"}); @@ -2711,14 +2820,14 @@ async function updateStatsRedisCluster(req, res) { } -async function updateStatsRedisClusterCommand(connectionId,clusterId) { +async function updateStatsRedisClusterCommand(connectionId,clusterId, clusterType) { try { var nodes = dbRedisCluster["$" + connectionId]["$" + clusterId]; for (let nodeId of Object.keys(nodes)) { - if (nodeId != "cluster" ) + if (nodeId != "cluster" && nodeId != "property") updateStatsRedisNode("$" + connectionId, "$" + clusterId, nodeId ); } @@ -2730,6 +2839,68 @@ async function updateStatsRedisClusterCommand(connectionId,clusterId) { } } +async function updateStatusRedisCluster(connectionId, clusterId, clusterType) { + + try + { + if (clusterType == "elasticache") { + var parameter = { + MaxRecords: 100, + ReplicationGroupId: clusterId + }; + + var clusterInfo = await elasticache.describeReplicationGroups(parameter).promise(); + if (clusterInfo.ReplicationGroups.length> 0) { + dbRedisCluster["$" + connectionId]["$" + clusterId]["property"]["status"] = clusterInfo.ReplicationGroups[0]["Status"]; + dbRedisCluster["$" + connectionId]["$" + clusterId]["property"]["size"] = clusterInfo.ReplicationGroups[0]["CacheNodeType"]; + dbRedisCluster["$" + connectionId]["$" + clusterId]["property"]["shards"] = clusterInfo.ReplicationGroups[0]["NodeGroups"].length; + dbRedisCluster["$" + connectionId]["$" + clusterId]["property"]["nodes"] = clusterInfo.ReplicationGroups[0]["MemberClusters"].length; + } + else { + dbRedisCluster["$" + connectionId]["$" + clusterId]["property"]["status"] = "pending"; + dbRedisCluster["$" + connectionId]["$" + clusterId]["property"]["size"] = "-"; + dbRedisCluster["$" + connectionId]["$" + clusterId]["property"]["shards"] = 0; + dbRedisCluster["$" + connectionId]["$" + clusterId]["property"]["nodes"] = 0; + } + + } + else { + var parameter = { + ClusterName: clusterId, + ShowShardDetails: true + }; + + var clusterInfo = await memorydb.describeClusters(parameter).promise(); + + if (clusterInfo.Clusters.length> 0) { + + var iNodes = 0; + clusterInfo.Clusters[0]["Shards"].forEach((shard) => { + iNodes = iNodes + shard["NumberOfNodes"]; + }); + + dbRedisCluster["$" + connectionId]["$" + clusterId]["property"]["status"] = clusterInfo.Clusters[0]["Status"]; + dbRedisCluster["$" + connectionId]["$" + clusterId]["property"]["size"] = clusterInfo.Clusters[0]["NodeType"]; + dbRedisCluster["$" + connectionId]["$" + clusterId]["property"]["shards"] = clusterInfo.Clusters[0]["NumberOfShards"]; + dbRedisCluster["$" + connectionId]["$" + clusterId]["property"]["nodes"] = iNodes; + } + else { + dbRedisCluster["$" + connectionId]["$" + clusterId]["property"]["status"] = "pending"; + dbRedisCluster["$" + connectionId]["$" + clusterId]["property"]["size"] = "-"; + dbRedisCluster["$" + connectionId]["$" + clusterId]["property"]["shards"] = 0; + dbRedisCluster["$" + connectionId]["$" + clusterId]["property"]["nodes"] = 0; + } + + } + + + } + catch(err){ + console.log(err); + } +} + + async function updateStatsRedisNode(connectionId,clusterId,nodeId) { @@ -2775,9 +2946,9 @@ async function updateStatsRedisNode(connectionId,clusterId,nodeId) { }); - + var jsonCommands = JSON.parse('{' + dataResult.slice(0, -1) + ' } '); - + dbRedisCluster[connectionId][clusterId][nodeId]["property"]["role"] = jsonInfo['role']; dbRedisCluster[connectionId][clusterId][nodeId]["node"].newSnapshot({ name : "", role : jsonInfo['role'], @@ -2796,12 +2967,18 @@ async function updateStatsRedisNode(connectionId,clusterId,nodeId) { setLatency: 0, keyspaceHits: parseFloat(jsonInfo['keyspace_hits']), keyspaceMisses: parseFloat(jsonInfo['keyspace_misses']), - netIn: parseFloat(jsonInfo['instantaneous_input_kbps']), - netOut: parseFloat(jsonInfo['instantaneous_output_kbps']), + netIn: parseFloat(jsonInfo['total_net_input_bytes']), + netOut: parseFloat(jsonInfo['total_net_output_bytes']), connectionsTotal: parseFloat(jsonInfo['total_connections_received']), commands: parseFloat(jsonInfo['total_commands_processed']), + cmdExec: (( jsonCommands.hasOwnProperty('cmdstat_exec') ) ? parseFloat(jsonCommands['cmdstat_exec']['calls']) : 0) , + cmdAuth: (( jsonCommands.hasOwnProperty('cmdstat_auth') ) ? parseFloat(jsonCommands['cmdstat_auth']['calls']) : 0) , + cmdInfo: (( jsonCommands.hasOwnProperty('cmdstat_info') ) ? parseFloat(jsonCommands['cmdstat_info']['calls']) : 0) , + cmdScan: (( jsonCommands.hasOwnProperty('cmdstat_scan') ) ? parseFloat(jsonCommands['cmdstat_scan']['calls']) : 0) , + cmdXadd: (( jsonCommands.hasOwnProperty('cmdstat_xadd') ) ? parseFloat(jsonCommands['cmdstat_xadd']['calls']) : 0) , + cmdZadd: (( jsonCommands.hasOwnProperty('cmdstat_zadd') ) ? parseFloat(jsonCommands['cmdstat_zadd']['calls']) : 0) , + keys : 0, timestamp : 0 - }, timeNow.getTime()); @@ -2809,7 +2986,14 @@ async function updateStatsRedisNode(connectionId,clusterId,nodeId) { } catch(err){ + console.log(err); + try { + //-- Node Status + dbRedisCluster[connectionId][clusterId][nodeId]["property"]["role"] = "-"; + } + catch(err) { console.log(err); + } } } @@ -2846,25 +3030,35 @@ async function gatherStatsRedisCluster(req, res) { network : 0, connectionsTotal: 0, commands: 0, + nodesGet : 0, + nodesSet : 0, + nodesHit : 0, + cmdExec: 0, + cmdAuth: 0, + cmdInfo: 0, + cmdScan: 0, + cmdXadd: 0, + cmdZadd: 0, + keys : 0, }; var nodesInfo = []; var totalNodes = 0; for (let nodeId of Object.keys(nodes)) { - if (nodeId != "cluster" ) { + if (nodeId != "cluster" && nodeId != "property" ) { var currentNode = dbRedisCluster[connectionId][clusterId][nodeId]["node"]; var nodeNetworkRate = dbRedisCluster[connectionId][clusterId][nodeId]["property"]['nodeNetworkRate']; dbRedisCluster[connectionId][clusterId][nodeId]["node"].addPropertyValue('cpu',(currentNode.getDeltaByIndex("cpuUser") * 100 ) + (currentNode.getDeltaByIndex("cpuSys") * 100 )); dbRedisCluster[connectionId][clusterId][nodeId]["node"].addPropertyValue('memory',(currentNode.getValueByIndex("memoryUsed")/currentNode.getValueByIndex("memoryTotal") ) * 100); - dbRedisCluster[connectionId][clusterId][nodeId]["node"].addPropertyValue('netin',currentNode.getValueByIndex("netIn") * 1024); - dbRedisCluster[connectionId][clusterId][nodeId]["node"].addPropertyValue('netout',currentNode.getValueByIndex("netOut") * 1024); + dbRedisCluster[connectionId][clusterId][nodeId]["node"].addPropertyValue('netin',currentNode.getDeltaByIndex("netIn")); + dbRedisCluster[connectionId][clusterId][nodeId]["node"].addPropertyValue('netout',currentNode.getDeltaByIndex("netOut")); dbRedisCluster[connectionId][clusterId][nodeId]["node"].addPropertyValue('network', ( ( - (currentNode.getValueByIndex("netOut") + currentNode.getValueByIndex("netIn") ) * 1024 + (currentNode.getDeltaByIndex("netOut") + currentNode.getDeltaByIndex("netIn") ) ) / nodeNetworkRate ) * 100 ); @@ -2886,7 +3080,7 @@ async function gatherStatsRedisCluster(req, res) { var nodeStats = { name : currentNode.getObjectName(), nodeId : currentNode.getObjectId(), - role : currentNode.getValueByIndex("role"), + role : dbRedisCluster[connectionId][clusterId][nodeId]["property"]["role"], cpu: (currentNode.getDeltaByIndex("cpuUser") * 100 ) + (currentNode.getDeltaByIndex("cpuSys") * 100 ), memory: (currentNode.getValueByIndex("memoryUsed")/currentNode.getValueByIndex("memoryTotal") ) * 100, memoryUsed: currentNode.getValueByIndex("memoryUsed"), @@ -2902,11 +3096,18 @@ async function gatherStatsRedisCluster(req, res) { cacheHitRate: (currentNode.getDeltaByIndex("keyspaceHits") / ( currentNode.getDeltaByIndex("keyspaceHits") + currentNode.getDeltaByIndex("keyspaceMisses")) ) * 100, - netIn: currentNode.getValueByIndex("netIn") * 1024, - netOut: currentNode.getValueByIndex("netOut") * 1024, - network : ( ( ( currentNode.getValueByIndex("netIn") + currentNode.getValueByIndex("netOut")) * 1024 ) / nodeNetworkRate ) * 100, + netIn: currentNode.getDeltaByIndex("netIn"), + netOut: currentNode.getDeltaByIndex("netOut"), + network : ( ( ( currentNode.getDeltaByIndex("netIn") + currentNode.getDeltaByIndex("netOut")) ) / nodeNetworkRate ) * 100, connectionsTotal: currentNode.getDeltaByIndex("connectionsTotal"), commands: currentNode.getDeltaByIndex("commands"), + cmdExec: currentNode.getDeltaByIndex("cmdExec"), + cmdAuth: currentNode.getDeltaByIndex("cmdAuth"), + cmdInfo: currentNode.getDeltaByIndex("cmdInfo"), + cmdScan: currentNode.getDeltaByIndex("cmdScan"), + cmdXadd: currentNode.getDeltaByIndex("cmdXadd"), + cmdZadd: currentNode.getDeltaByIndex("cmdZadd"), + keys : 0, history : { cpu : dbRedisCluster[connectionId][clusterId][nodeId]["node"].getPropertyValues('cpu'), memory : dbRedisCluster[connectionId][clusterId][nodeId]["node"].getPropertyValues('memory'), @@ -2948,7 +3149,17 @@ async function gatherStatsRedisCluster(req, res) { clusterInfo.network = clusterInfo.network + ( nodeStats.network || 0 ); clusterInfo.connectionsTotal = clusterInfo.connectionsTotal + ( nodeStats.connectionsTotal || 0 ); clusterInfo.commands = clusterInfo.commands + ( nodeStats.commands || 0 ); - + clusterInfo.nodesGet = clusterInfo.nodesGet + ( ( nodeStats.getLatency || 0 ) > 0 ? 1 : 0); + clusterInfo.nodesSet = clusterInfo.nodesSet + ( ( nodeStats.setLatency || 0 ) > 0 ? 1 : 0); + clusterInfo.nodesHit = clusterInfo.nodesHit + ( ( nodeStats.cacheHitRate || 0 ) > 0 ? 1 : 0); + clusterInfo.cmdExec = clusterInfo.cmdExec + ( nodeStats.cmdExec || 0 ); + clusterInfo.cmdAuth = clusterInfo.cmdAuth + ( nodeStats.cmdAuth || 0 ); + clusterInfo.cmdInfo = clusterInfo.cmdInfo + ( nodeStats.cmdInfo || 0 ); + clusterInfo.cmdScan = clusterInfo.cmdScan + ( nodeStats.cmdScan || 0 ); + clusterInfo.cmdXadd = clusterInfo.cmdXadd + ( nodeStats.cmdXadd || 0 ); + clusterInfo.cmdZadd = clusterInfo.cmdZadd + ( nodeStats.cmdZadd || 0 ); + clusterInfo.keys = clusterInfo.keys + ( nodeStats.keys || 0 ); + totalNodes++; @@ -2960,9 +3171,9 @@ async function gatherStatsRedisCluster(req, res) { clusterInfo.cpu = clusterInfo.cpu / totalNodes; clusterInfo.memory = clusterInfo.memory / totalNodes; clusterInfo.network = clusterInfo.network / totalNodes; - clusterInfo.getLatency = clusterInfo.getLatency / totalNodes; - clusterInfo.setLatency = clusterInfo.setLatency / totalNodes; - clusterInfo.cacheHitRate = clusterInfo.cacheHitRate / totalNodes; + clusterInfo.getLatency = clusterInfo.getLatency / clusterInfo.nodesGet; + clusterInfo.setLatency = clusterInfo.setLatency / clusterInfo.nodesSet; + clusterInfo.cacheHitRate = clusterInfo.cacheHitRate / clusterInfo.nodesHit; dbRedisCluster[connectionId][clusterId]["cluster"].addPropertyValue('operations',clusterInfo.operations); dbRedisCluster[connectionId][clusterId]["cluster"].addPropertyValue('getCalls',clusterInfo.getCalls); @@ -2974,6 +3185,10 @@ async function gatherStatsRedisCluster(req, res) { res.status(200).send( { cluster : { + status : dbRedisCluster[connectionId][clusterId]["property"]["status"], + size : dbRedisCluster[connectionId][clusterId]["property"]["size"], + shards : dbRedisCluster[connectionId][clusterId]["property"]["shards"], + nodes : dbRedisCluster[connectionId][clusterId]["property"]["nodes"], ...clusterInfo, history : { operations : dbRedisCluster[connectionId][clusterId]["cluster"].getPropertyValues('operations'), @@ -3010,13 +3225,15 @@ async function closeRedisConnectionAll(req, res) { for (let nodeId of Object.keys(nodes)) { try { - if (nodeId != "cluster" ) { + if (nodeId != "cluster" && nodeId != "property" ) { console.log("Redis Disconnection : " + params.connectionId + " # " + params.clusterId + " # " + nodeId ); - nodes[nodeId]["connection"].quit(); + if (nodes[nodeId]["connection"].isReady) + nodes[nodeId]["connection"].quit(); } } - catch{ + catch(err){ console.log("Redis Disconnection error : " + params.connectionId + " # " + params.clusterId + " # " + nodeId ); + console.log(err); } } @@ -3084,7 +3301,7 @@ async function authDocumentDBConnection(req, res) { ] ) ; documentDBCluster["$" + session_id][ "$" + params.clusterId]["property"] = function(){}; - documentDBCluster["$" + session_id][ "$" + params.clusterId]["property"] = { clusterId: params.clusterId, timestamp : "" } + documentDBCluster["$" + session_id][ "$" + params.clusterId]["property"] = { clusterId: params.clusterId, timestamp : "", status : "pending", nodes : 0 } await client.close(); @@ -3309,7 +3526,7 @@ async function updateStatsDocumentDBCluster(req, res) { try { var params = req.query; - + updateStatusDocumentCluster(params.connectionId, params.clusterId); var nodes = documentDBCluster["$" + params.connectionId]["$" + params.clusterId]; for (let nodeId of Object.keys(nodes)) { if (nodeId != "cluster" && nodeId != "property" ){ @@ -3327,6 +3544,27 @@ async function updateStatsDocumentDBCluster(req, res) { } +async function updateStatusDocumentCluster(connectionId,clusterId) { + + try { + var parameterCluster = { + DBClusterIdentifier: clusterId, + MaxRecords: 100 + }; + + var clusterData = await docDB.describeDBClusters(parameterCluster).promise(); + documentDBCluster["$" + connectionId]["$" + clusterId]["property"]["status"] = clusterData['DBClusters'][0]['Status']; + documentDBCluster["$" + connectionId]["$" + clusterId]["property"]["nodes"] =clusterData['DBClusters'][0]['DBClusterMembers'].length; + } + catch(err){ + documentDBCluster["$" + connectionId]["$" + clusterId]["property"]["status"] = "pending"; + documentDBCluster["$" + connectionId]["$" + clusterId]["property"]["nodes"] = 0; + console.log(err); + } + +} + + async function updateStatsDocumentDBNode(connectionId,clusterId,nodeId, resourceId, monitoring) { @@ -3347,7 +3585,6 @@ async function updateStatsDocumentDBNode(connectionId,clusterId,nodeId, resource if (instanceData.DBInstances.length > 0) { instanceInfo.status = instanceData.DBInstances[0]['DBInstanceStatus']; instanceInfo.size = instanceData.DBInstances[0]['DBInstanceClass']; - } //-- Current Operations @@ -3404,6 +3641,9 @@ async function updateStatsDocumentDBNode(connectionId,clusterId,nodeId, resource } catch(err){ + documentDBCluster[connectionId][clusterId][nodeId]["property"]["status"] = "pending"; + documentDBCluster[connectionId][clusterId][nodeId]["property"]["role"] = "-"; + documentDBCluster[connectionId][clusterId][nodeId]["property"]["size"] = "-"; console.log(err); } @@ -3803,6 +4043,8 @@ async function gatherStatsDocumentDBCluster(req, res) { res.status(200).send( { cluster : { + status : documentDBCluster[connectionId][clusterId]["property"]["status"], + nodes : documentDBCluster[connectionId][clusterId]["property"]["nodes"], ...clusterInfo, history : { cpu: documentDBCluster[connectionId][clusterId]["cluster"].getPropertyValues('cpu'), diff --git a/server/package.json b/server/package.json index e4bd4cc..b3d472f 100644 --- a/server/package.json +++ b/server/package.json @@ -24,6 +24,7 @@ "mssql": "^9.1.2", "mysql": "^2.18.1", "mysql2": "^3.6.1", + "node-schedule": "^2.1.1", "oracledb": "^6.0.3", "pg": "^8.9.0", "redis": "^4.6.7",