♻️ remove the nodejs version agent, rewrite in Golang

This commit is contained in:
Tony An
2024-05-10 19:37:40 -05:00
parent 4ed613bf2c
commit 4a05ee22be
37 changed files with 1431 additions and 7406 deletions

166
InfrastructureAgent/.gitignore vendored Normal file
View File

@@ -0,0 +1,166 @@
dist/
releases/
data/
bin/
web/node_modules/
web/dist/
*.log
### JetBrains
.idea/
.fleet/
wshop-pay.iml
### VisualStudioCode template
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.code-workspace
tmp/
# Local History for Visual Studio Code
.history/
web/templates/**/node_modules
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
### Go template
# Binaries for programs and plugins
*.dll
*.so
*.dylib
# Test binary, built with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Dependency directories (remove the comment below to include it)
# vendor/
### Vim template
# Swap
[._]*.s[a-v][a-z]
!*.svg # comment out if you don't need vector files
[._]*.sw[a-p]
[._]s[a-rt-v][a-z]
[._]ss[a-gi-z]
[._]sw[a-p]
# Session
Session.vim
Sessionx.vim
# Temporary
.netrwhist
*~
# Auto-generated tag files
tags
# Persistent undo
[._]*.un~
### Archives template
# It's better to unpack these files and commit the raw source because
# git has its own built in compression methods.
*.7z
*.jar
*.rar
*.zip
*.gz
*.gzip
*.tgz
*.bzip
*.bzip2
*.bz2
*.xz
*.lzma
*.cab
*.xar
# Packing-only formats
*.iso
*.tar
# Package management formats
*.dmg
*.xpi
*.gem
*.egg
*.deb
*.rpm
*.msi
*.msm
*.msp
*.txz
### macOS template
# 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
/web/tsconfig.tsbuildinfo

View File

@@ -0,0 +1,45 @@
# This is an example .goreleaser.yml file with some sensible defaults.
# Make sure to check the documentation at https://goreleaser.com
# The lines below are called `modelines`. See `:help modeline`
# Feel free to remove those if you don't want/need to use them.
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
# vim: set ts=2 sw=2 tw=0 fo=cnqoj
version: 1
before:
hooks:
# You may remove this if you don't use go modules.
- go mod tidy
- go mod download
env:
- CGO_ENABLED=0
builds:
- binary: oneuptime-infrastructure-agent
main: ./cmd
goos:
- linux
- windows
- darwin
- freebsd
- openbsd
goarch:
- amd64
- arm64
goarm:
- 6
- 7
archives:
- format: tar.gz
# this name template makes the OS and Arch compatible with the results of `uname`.
name_template: '{{ .Binary }}_{{ .Os }}_{{ .Arch }}'
format_overrides:
- goos: windows
format: zip
changelog:
sort: asc
filters:
exclude:
- "^docs:"
- "^test:"

View File

@@ -1,76 +0,0 @@
#
# OneUptime-App Dockerfile
#
# Pull base image nodejs image.
FROM node:21.2-alpine3.18
RUN mkdir /tmp/npm && chmod 2777 /tmp/npm && chown 1000:1000 /tmp/npm && npm config set cache /tmp/npm --global
ARG GIT_SHA
ARG APP_VERSION
ENV GIT_SHA=${GIT_SHA}
ENV APP_VERSION=${APP_VERSION}
# IF APP_VERSION is not set, set it to 1.0.0
RUN if [ -z "$APP_VERSION" ]; then export APP_VERSION=1.0.0; fi
# Install bash.
RUN apk add bash && apk add curl
# Install python
RUN apk update && apk add --no-cache --virtual .gyp python3 make g++
#Use bash shell by default
SHELL ["/bin/bash", "-c"]
RUN mkdir /usr/src
WORKDIR /usr/src/Common
COPY ./Common/package*.json /usr/src/Common/
# Set version in ./Common/package.json to the APP_VERSION
RUN sed -i "s/\"version\": \".*\"/\"version\": \"$APP_VERSION\"/g" /usr/src/Common/package.json
RUN npm install
COPY ./Common /usr/src/Common
WORKDIR /usr/src/Model
COPY ./Model/package*.json /usr/src/Model/
# Set version in ./Model/package.json to the APP_VERSION
RUN sed -i "s/\"version\": \".*\"/\"version\": \"$APP_VERSION\"/g" /usr/src/Model/package.json
RUN npm install
COPY ./Model /usr/src/Model
WORKDIR /usr/src/CommonServer
COPY ./CommonServer/package*.json /usr/src/CommonServer/
# Set version in ./CommonServer/package.json to the APP_VERSION
RUN sed -i "s/\"version\": \".*\"/\"version\": \"$APP_VERSION\"/g" /usr/src/CommonServer/package.json
RUN npm install
COPY ./CommonServer /usr/src/CommonServer
ENV PRODUCTION=true
WORKDIR /usr/src/app
# Install app dependencies
COPY ./InfrastructureAgent/package*.json /usr/src/app/
RUN npm install
{{ if eq .Env.ENVIRONMENT "development" }}
#Run the app
CMD [ "npm", "run", "dev" ]
{{ else }}
# Copy app source
COPY ./InfrastructureAgent /usr/src/app
# Bundle app source
RUN npm run compile
#Run the app
CMD [ "npm", "start" ]
{{ end }}

View File

@@ -1,203 +0,0 @@
#!/usr/bin/env tsx
import yargs from 'yargs';
import { ChildProcess, spawn } from 'node:child_process';
import Logger from './Utils/Logger';
import PackageJson from './package.json';
import MonitorInfrastructure from './Jobs/MonitorInfrastructure';
import fs from 'fs';
export interface ArgumentType {
[x: string]: unknown;
k: string;
u: string | undefined;
_: (string | number)[];
$0: string;
}
const usage: string =
'\nUsage: oneuptime-infrastructure-agent start --secret-key <secret-key>.';
const returnValue:
| {
[x: string]: unknown;
_: (string | number)[];
$0: string;
}
| Promise<{
[x: string]: unknown;
_: (string | number)[];
$0: string;
}> = yargs
.scriptName('oneuptime-infrastructure-agent')
.usage(usage)
.version(PackageJson.version)
.command(
'start',
'Start the app as a daemon',
(y: any) => {
return y
.option('k', {
alias: 'secret-key',
describe:
'Secret Key for this agent. You will find this on OneUptime Dashboard',
type: 'string',
demandOption: true,
})
.option('u', {
alias: 'oneuptime-url',
describe:
'OneUptime Host. By default this is https://oneuptime.com',
type: 'string',
demandOption: false,
});
},
async (y: yargs.ArgumentsCamelCase) => {
const argv: ArgumentType = y as ArgumentType;
// add secrt key and oneuptime url
const startArguments: Array<string> = ['Start.ts'];
const secretKey: string | undefined = argv['secret-key'] as
| string
| undefined;
if (secretKey) {
startArguments.push('--secret-key=' + secretKey.toString());
} else {
Logger.info(
'No --secret-key argument found. You can find secret key for this monitor on OneUptime Dashboard'
);
process.exit(1);
}
const oneuptimeUrl: string | undefined =
(argv['oneuptime-url'] as string | undefined) ||
'https://oneuptime.com';
startArguments.push('--oneuptime-url=' + oneuptimeUrl.toString());
// before we run as daemon, we need to verify if the credentials are correct
try {
const isValidSecretKey: boolean =
await MonitorInfrastructure.checkIfSecretKeyIsValid({
oneuptimeUrl: oneuptimeUrl,
secretKey: secretKey,
});
if (!isValidSecretKey) {
Logger.error('Invalid secret key or OneUptime URL');
process.exit(1);
}
const out: number = fs.openSync('./out.log', 'a');
const err: number = fs.openSync('./err.log', 'a');
// clean up logs
fs.writeFileSync('./out.log', '');
fs.writeFileSync('./err.log', '');
const daemon: ChildProcess = spawn('tsx', startArguments, {
detached: true,
stdio: ['ignore', out, err],
});
// save the process id to a file
fs.writeFileSync('./daemon.pid', daemon?.pid?.toString() || '');
daemon.unref();
Logger.info('OneUptime Infrastructure Agent started as daemon');
} catch (err) {
Logger.error(err);
process.exit(1);
}
}
)
.command(
'stop',
'Stop the daemon',
() => {},
() => {
// read the pid from file
let pid: string | number = fs
.readFileSync('./daemon.pid', 'utf-8')
.trim();
if (pid) {
if (typeof pid === 'string') {
pid = parseInt(pid);
}
process.kill(pid);
// remove the pid file
fs.unlinkSync('./daemon.pid');
Logger.info('OneUptime Infrastructure Agent stopped');
} else {
Logger.info('OneUptime Infrastructure Agent not running');
}
}
)
.command(
'status',
'Show status of daemon',
() => {},
() => {
// check if daemon.pid file exists
const doesFileExist: boolean = fs.existsSync('./daemon.pid');
if (!doesFileExist) {
Logger.info('OneUptime Infrastructure Agent is not running');
return;
}
const pid: string | number = fs
.readFileSync('./daemon.pid', 'utf-8')
.trim();
if (pid) {
Logger.info('OneUptime Infrastructure Agent is running');
} else {
Logger.info('OneUptime Infrastructure Agent is not running');
}
}
)
.command(
'logs',
'Show logs',
() => {},
() => {
// show logs from daemon
const pid: string | number = fs
.readFileSync('./daemon.pid', 'utf-8')
.trim();
if (pid) {
const logs: string = fs.readFileSync('./out.log', 'utf-8');
Logger.info(logs);
} else {
Logger.info('OneUptime Infrastructure Agent is not running');
}
}
)
.command(
'$0',
'the default command',
() => {},
() => {
yargs.showHelp();
}
)
.help(true).argv;
if (returnValue instanceof Promise) {
returnValue.catch((err: Error) => {
Logger.error(err);
process.exit(1);
});
}

View File

@@ -1,93 +0,0 @@
import ServerMonitorResponse from '../Types/ServerMonitorResponse';
import BasicCron from '../Utils/BasicCron';
import { BasicMetircs } from '../Utils/BasicMetrics';
import Logger from '../Utils/Logger';
import axios, { AxiosResponse } from 'axios';
import ServerProcessUtil from '../Utils/ServerProcess';
export default class MonitorInfrastructure {
public static initJob(secretKey: string, oneuptimeUrl: string): void {
const EVERY_MINUTE: string = '* * * * *';
BasicCron({
jobName: 'MonitorInfrastructure',
options: {
schedule: EVERY_MINUTE, // Every minute
runOnStartup: true,
},
runFunction: async () => {
await MonitorInfrastructure.monitorServerMetrics({
oneuptimeUrl: oneuptimeUrl,
secretKey: secretKey,
});
},
});
}
public static async checkIfSecretKeyIsValid(data: {
oneuptimeUrl: string;
secretKey: string;
}): Promise<boolean> {
try {
const { oneuptimeUrl, secretKey } = data;
if (!secretKey) {
throw new Error(
'No SECRET_KEY environment variable found. You can find secret key for this monitor on OneUptime Dashboard'
);
}
const response: AxiosResponse = await axios.get(
`${oneuptimeUrl}/server-monitor/secret-key/verify/${secretKey}`
);
if (response.status === 200) {
return true;
}
return false;
} catch (err) {
Logger.error(err);
return false;
}
}
public static async monitorServerMetrics(data: {
oneuptimeUrl: string;
secretKey: string;
}): Promise<void> {
try {
const { oneuptimeUrl, secretKey } = data;
if (!secretKey) {
throw new Error(
'No SECRET_KEY environment variable found. You can find secret key for this monitor on OneUptime Dashboard'
);
}
const serverMonitorResponse: ServerMonitorResponse = {
secretKey: secretKey,
requestReceivedAt: new Date(),
basicInfrastructureMetrics:
await BasicMetircs.getBasicMetrics(),
processes: await ServerProcessUtil.getServerProcesses(),
onlyCheckRequestReceivedAt: false,
};
Logger.info('Server Monitor Response');
Logger.info(JSON.stringify(serverMonitorResponse, null, 2));
// now we send this data back to server.
await axios.post(
`${oneuptimeUrl}/server-monitor/response/ingest/${secretKey}`,
{
serverMonitorResponse: serverMonitorResponse,
},
{}
);
} catch (err) {
Logger.error(err);
}
}
}

201
InfrastructureAgent/LICENSE Normal file
View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

52
InfrastructureAgent/README.md Executable file → Normal file
View File

@@ -1,55 +1,53 @@
# OneUptime Infrastructure Agent
# OneUptime Infrastructure Agent (go)
The OneUptime Infrastructure Agent is a lightweight, open-source agent that collects system metrics and sends them to the OneUptime platform. It is designed to be easy to install and use, and to be extensible.
## Installation
```
npm i @oneuptime/infrastructure-agent -g
# You can change the host to your own host if you're self hosting the OneUptime platform.
# You can find the secret key on OneUptime Dashboard. Click on "View Monitor" and go to "Settings" tab.
oneuptime-infrastructure-agent start --secret-key=YOUR_SECRET_KEY --oneuptime-url=https://oneuptime.com
Download the Installation Script
```bash
curl -O https://raw.githubusercontent.com/anxuanzi/oneuptime-infrastructure-agent-go/main/install.sh
```
Run the Installation Script
```bash
chmod +x install.sh && ./install.sh
```
Install the agent as a system service
- You can change the host to your own host if you're self hosting the OneUptime platform.
- You can find the secret key on OneUptime Dashboard. Click on "View Monitor" and go to "Settings" tab.
```bash
oneuptime-infrastructure-agent install --secret-key=YOUR_SECRET_KEY --oneuptime-url=https://oneuptime.com
```
## Starting the agent
```
oneuptime-infrastructure-agent start
```
Once its up and running you should see the metrics on the OneUptime Dashboard.
## Stopping the agent
```
oneuptime-infrastructure-agent stop
```
## Check the status of the agent
## Restarting the agent
```
oneuptime-infrastructure-agent status
```
## Logs
```
oneuptime-infrastructure-agent logs
oneuptime-infrastructure-agent restart
```
## Uninstalling the agent
```
npm uninstall -g @oneuptime/infrastructure-agent
oneuptime-infrastructure-agent uninstall && rm -rf /usr/bin/oneuptime-infrastructure-agent
```
## Supported Platforms
- Linux
- MacOS
- Windows
## Local Development
When you're developing locally, you can run the agent in development mode to send metrics to local oneuptime server.
```
npm run start -- --secret-key=YOUR_SECRET_KEY --oneuptime-url=http://localhost
```
- Windows

View File

@@ -1,11 +0,0 @@
cd ..
cd Common && npm install && cd ..
cd Model && npm install && cd ..
cd CommonServer && npm install && cd ..
cd CommonUI && npm install --force && cd ..
cd InfrastructureAgent
npm install
npm run compile
npm run build
npm i postject -g

View File

@@ -1,7 +0,0 @@
# This is taken from: https://nodejs.org/api/single-executable-applications.html
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
bash $SCRIPT_DIR/Base.sh
node --experimental-sea-config $SCRIPT_DIR/../../sea-config.json
cp $(command -v node) InfrastructureAgent
npx postject InfrastructureAgent NODE_SEA_BLOB sea-prep.blob \
--sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2

View File

@@ -1,11 +0,0 @@
# This is taken from: https://nodejs.org/api/single-executable-applications.html
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
bash $SCRIPT_DIR/Base.sh
node --experimental-sea-config $SCRIPT_DIR/../../sea-config.json
cp $(command -v node) InfrastructureAgent
codesign --remove-signature InfrastructureAgent
npx postject InfrastructureAgent NODE_SEA_BLOB sea-prep.blob \
--sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2 \
--macho-segment-name NODE_SEA
codesign --sign - InfrastructureAgent

View File

@@ -1,13 +0,0 @@
# This is taken from: https://nodejs.org/api/single-executable-applications.html
# Run Base.sh
# This is a PowerShell script that builds the Windows version of the Infrastructure Agent.
SET SCRIPT_DIR=%~dp0
Write-Host "Scirpt Directory: $SCRIPT_DIR"
bash $SCRIPT_DIR/Base.sh
node --experimental-sea-config $SCRIPT_DIR/../../sea-config.json
node -e "require('fs').copyFileSync(process.execPath, 'InfrastructureAgent.exe')"
signtool remove /s InfrastructureAgent.exe
npx postject InfrastructureAgent.exe NODE_SEA_BLOB sea-prep.blob `
--sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2
signtool sign /fd SHA256 InfrastructureAgent.exe

View File

@@ -1,14 +0,0 @@
import MonitorInfrastructure from './Jobs/MonitorInfrastructure';
import { argv } from 'yargs';
const secretKey: string | undefined = (argv as any)['secret-key'];
const oneuptimeUrl: string =
(argv as any)['oneuptime-url'] || 'https://oneuptime.com';
if (!secretKey) {
throw new Error(
'No secret-key argument found. You can find secret key for this monitor on OneUptime Dashboard'
);
}
MonitorInfrastructure.initJob(secretKey, oneuptimeUrl);

View File

@@ -1,26 +0,0 @@
export interface MemoryMetrics {
total: number;
free: number;
used: number;
percentUsed: number;
percentFree: number;
}
export interface CPUMetrics {
percentUsed: number;
}
export interface BasicDiskMetrics {
total: number;
free: number;
used: number;
diskPath: string;
percentUsed: number;
percentFree: number;
}
export default interface BasicInfrastructureMetrics {
cpuMetrics: CPUMetrics;
memoryMetrics: MemoryMetrics;
diskMetrics: Array<BasicDiskMetrics>;
}

View File

@@ -1,15 +0,0 @@
import BasicInfrastructureMetrics from './BasicMetrics';
export interface ServerProcess {
pid: number;
name: string;
command: string;
}
export default interface ServerMonitorResponse {
secretKey: string;
basicInfrastructureMetrics?: BasicInfrastructureMetrics | undefined;
requestReceivedAt: Date;
onlyCheckRequestReceivedAt: boolean;
processes?: ServerProcess[] | undefined;
}

View File

@@ -1,37 +0,0 @@
import logger from './Logger';
import cron from 'node-cron';
type BasicCronProps = {
jobName: string;
options: {
schedule: string;
runOnStartup: boolean;
};
runFunction: () => Promise<void>;
};
type BasicCronFunction = (props: BasicCronProps) => void;
const BasicCron: BasicCronFunction = async (
props: BasicCronProps
): Promise<void> => {
const { jobName, options, runFunction } = props;
cron.schedule(options.schedule, async () => {
try {
logger.info(`Job ${jobName} Start`);
await runFunction();
logger.info(`Job ${jobName} End`);
} catch (e) {
logger.info(`Job ${jobName} Error`);
logger.error(e);
}
});
if (options.runOnStartup) {
logger.info(`Job ${jobName} - Start on Startup`);
await runFunction();
}
};
export default BasicCron;

View File

@@ -1,78 +0,0 @@
import os from 'node:os';
import diskusage from 'diskusage';
import BasicInfrastructureMetrics, {
BasicDiskMetrics,
CPUMetrics,
MemoryMetrics,
} from '../Types/BasicMetrics';
// This is a workaround for a bug in the type definitions of the drivelist package. import does not work.
const drivelist: any = require('drivelist');
export class BasicMetircs {
public static async getBasicMetrics(): Promise<BasicInfrastructureMetrics> {
const diskPaths: Array<string> = await this.getDiskPaths();
return {
memoryMetrics: await this.getMemoryMetrics(),
cpuMetrics: await this.getCPUMetrics(),
diskMetrics: await Promise.all(
diskPaths.map(async (diskPath: string) => {
return this.getDiskUsage(diskPath);
})
),
};
}
public static async getDiskPaths(): Promise<Array<string>> {
const drives: Array<any> = await drivelist.list();
const mountPoints: Array<string> = [];
for (const drive of drives) {
for (const mountPoint of drive.mountpoints) {
mountPoints.push(mountPoint.path);
}
}
// remove duplicates
return Array.from(new Set(mountPoints));
}
public static async getDiskUsage(
diskPath: string
): Promise<BasicDiskMetrics> {
const info: diskusage.DiskUsage = await diskusage.check(diskPath);
return {
total: info.total,
free: info.free,
used: info.total - info.free,
diskPath: diskPath,
percentFree: (info.free / info.total) * 100,
percentUsed: ((info.total - info.free) / info.total) * 100,
};
}
public static async getMemoryMetrics(): Promise<MemoryMetrics> {
const totalMemory: number = os.totalmem();
const freeMemory: number = os.freemem();
const usedMemory: number = totalMemory - freeMemory;
return {
total: totalMemory,
free: freeMemory,
used: usedMemory,
percentFree: (freeMemory / totalMemory) * 100,
percentUsed: (usedMemory / totalMemory) * 100,
};
}
public static async getCPUMetrics(): Promise<CPUMetrics> {
const cpuUsage: number | undefined = os.loadavg()[0]; // Returns an array containing the 1, 5, and 15 minute load averages.
return {
percentUsed: cpuUsage || 0,
};
}
}

View File

@@ -1,21 +0,0 @@
export default class Logger {
public static warn(text: string): void {
//eslint-disable-next-line
console.warn(text);
}
public static error(text: string | unknown): void {
//eslint-disable-next-line
console.error(text);
}
public static log(text: string): void {
//eslint-disable-next-line
console.log(text);
}
public static info(text: string): void {
//eslint-disable-next-line
this.log(text);
}
}

View File

@@ -1,24 +0,0 @@
import os from 'node:os';
enum OSTypeEnum {
Windows = 'Windows',
Linux = 'Linux',
MacOS = 'MacOS',
Unknown = 'Unknown',
}
export default class OSType {
public static getOSType(): OSTypeEnum {
const platform: string = os.type();
switch (platform) {
case 'Windows_NT':
return OSTypeEnum.Windows;
case 'Linux':
return OSTypeEnum.Linux;
case 'Darwin':
return OSTypeEnum.MacOS;
default:
return OSTypeEnum.Unknown;
}
}
}

View File

@@ -1,30 +0,0 @@
import psList from 'ps-list';
import { ServerProcess } from '../Types/ServerMonitorResponse';
import Logger from './Logger';
export default class ServerProcessUtil {
public static async getServerProcesses(): Promise<ServerProcess[]> {
try {
const processes: ServerProcess[] = [];
const processList: any[] = await psList();
for (const process of processList) {
processes.push({
pid: process.pid,
name: process.name,
command: process.command,
});
}
Logger.info('Server processes:');
Logger.info(JSON.stringify(processes, null, 2));
return processes;
} catch (err) {
Logger.error('Cannot get a list of server processes');
Logger.error(err);
return [];
}
}
}

View File

@@ -0,0 +1,146 @@
package oneuptime_InfrastructureAgent_go
import (
"encoding/json"
"github.com/go-co-op/gocron/v2"
"github.com/gookit/greq"
"github.com/gookit/slog"
"os"
"time"
)
type Agent struct {
SecretKey string
OneUptimeURL string
scheduler gocron.Scheduler
mainJob gocron.Job
shutdownHook Hook
}
func NewAgent(secretKey string, url string) *Agent {
ag := &Agent{
SecretKey: secretKey,
OneUptimeURL: url,
}
slog.Info("Starting agent...")
slog.Info("Agent configuration:")
slog.Info("Secret key: " + ag.SecretKey)
slog.Info("OneUptime URL: " + ag.OneUptimeURL)
if ag.SecretKey == "" || ag.OneUptimeURL == "" {
slog.Error("Secret key and OneUptime URL are required")
os.Exit(1)
return ag
}
// check if secret key is valid
if !checkIfSecretKeyIsValid(ag.SecretKey, ag.OneUptimeURL) {
slog.Error("Secret key is invalid")
os.Exit(1)
return ag
}
scheduler, err := gocron.NewScheduler()
if err != nil {
slog.Error(err)
os.Exit(1)
return ag
}
job, err := scheduler.NewJob(gocron.DurationJob(time.Minute), gocron.NewTask(collectMetricsJob, ag.SecretKey, ag.OneUptimeURL))
if err != nil {
slog.Error(err.Error())
os.Exit(1)
return ag
}
ag.scheduler = scheduler
ag.mainJob = job
return ag
}
func (ag *Agent) Start() {
ag.scheduler.Start()
err := ag.mainJob.RunNow()
if err != nil {
slog.Info(err.Error())
os.Exit(1)
return
}
}
func (ag *Agent) Close() {
err := ag.scheduler.Shutdown()
if err != nil {
slog.Error(err.Error())
}
}
func collectMetricsJob(secretKey string, oneuptimeURL string) {
memMetrics := getMemoryMetrics()
if memMetrics == nil {
slog.Warn("Failed to get memory metrics")
}
cpuMetrics := getCpuMetrics()
if cpuMetrics == nil {
slog.Warn("Failed to get CPU metrics")
}
diskMetrics := listDiskMetrics()
if diskMetrics == nil {
slog.Warn("Failed to get disk metrics")
}
servProcesses := getServerProcesses()
if servProcesses == nil {
slog.Warn("Failed to get server processes")
}
metricsReport := &ServerMonitorReport{
SecretKey: secretKey,
BasicInfrastructureMetrics: &BasicInfrastructureMetrics{
MemoryMetrics: memMetrics,
CpuMetrics: cpuMetrics,
DiskMetrics: diskMetrics,
},
RequestReceivedAt: time.Now().UTC().Format("2006-01-02T15:04:05.000Z"),
OnlyCheckRequestReceivedAt: false,
Processes: servProcesses,
}
reqData := struct {
ServerMonitorResponse *ServerMonitorReport `json:"serverMonitorResponse"`
}{
ServerMonitorResponse: metricsReport,
}
postBuilder := greq.New(oneuptimeURL).Post("/server-monitor/response/ingest/" + secretKey).
JSONType().JSONBody(reqData)
resp, err := postBuilder.Do()
if err != nil {
slog.Error(err.Error())
}
if resp.IsFail() {
slog.Error("Failed to ingest metrics with status code ", resp.StatusCode)
respJson, _ := json.Marshal(resp)
slog.Error("Response: ", string(respJson))
}
slog.Info("1 minute metrics have been sent to OneUptime.")
}
func checkIfSecretKeyIsValid(secretKey string, baseUrl string) bool {
if secretKey == "" {
slog.Error("Secret key is empty")
return false
}
resp, err := greq.New(baseUrl).JSONType().GetDo("/server-monitor/secret-key/verify/" + secretKey)
if err != nil {
slog.Error(err.Error())
return false
}
if resp.StatusCode != 200 {
slog.Error("Secret key verification failed with status code ", resp.StatusCode)
return false
}
return true
}

View File

@@ -0,0 +1,128 @@
package main
import (
"encoding/json"
"fmt"
"github.com/gookit/config/v2"
"github.com/gookit/slog"
"os"
"path/filepath"
"runtime"
)
type configFile struct {
SecretKey string `json:"secret_key"`
OneUptimeURL string `json:"oneuptime_url"`
}
func newConfigFile() *configFile {
return &configFile{
SecretKey: "",
OneUptimeURL: "",
}
}
func (c *configFile) loadConfig() error {
cfg := &configFile{}
err := config.LoadFiles(c.configPath())
if err != nil {
return err
}
err = config.BindStruct("", cfg)
if err != nil {
return err
}
c.SecretKey = cfg.SecretKey
c.OneUptimeURL = cfg.OneUptimeURL
return nil
}
func (c *configFile) save(secretKey string, url string) error {
err := c.loadConfig()
if err != nil && !os.IsNotExist(err) {
return err
}
err = config.Set("secret_key", secretKey)
if err != nil {
return err
}
err = config.Set("oneuptime_url", url)
if err != nil {
return err
}
// Open the file with os.Create, which truncates the file if it already exists,
// and creates it if it doesn't.
file, err := os.Create(c.configPath())
if err != nil {
return err
}
defer file.Close()
// Create a JSON encoder that writes to the file, and use Encode method
// which will write the map to the file in JSON format.
encoder := json.NewEncoder(file)
encoder.SetIndent("", " ") // Optional: makes the output more readable
return encoder.Encode(config.Data())
}
// removeConfigFile deletes the configuration file.
func (c *configFile) removeConfigFile() error {
// Check if the file exists before attempting to remove it.
if _, err := os.Stat(c.configPath()); os.IsNotExist(err) {
// File does not exist, return an error or handle it accordingly.
return os.ErrNotExist
}
// Remove the file.
err := os.Remove(c.configPath())
if err != nil {
// Handle potential errors in deleting the file.
return err
}
return nil
}
// ensureDir checks if a directory exists and makes it if it does not.
func (c *configFile) ensureDir(dirName string) error {
// Check if the directory exists
info, err := os.Stat(dirName)
if os.IsNotExist(err) {
// Directory does not exist, create it
return os.MkdirAll(dirName, 0755)
}
if err != nil {
return err
}
if !info.IsDir() {
// Exists but is not a directory
return os.ErrExist
}
return nil
}
// configPath returns the full path to the configuration file,
// ensuring the directory exists or creating it if it does not.
func (c *configFile) configPath() string {
var basePath string
if runtime.GOOS == "windows" {
basePath = os.Getenv("PROGRAMDATA")
if basePath == "" {
basePath = fmt.Sprintf("C:%sProgramData", string(filepath.Separator))
}
} else {
basePath = fmt.Sprintf("%setc", string(filepath.Separator))
}
// Define the directory path where the configuration file will be stored.
configDirectory := filepath.Join(basePath, "oneuptime_infrastructure_agent")
// Ensure the directory exists.
err := c.ensureDir(configDirectory)
if err != nil {
slog.Fatalf("Failed to create config directory: %v", err)
}
// Return the full path to the configuration file.
return filepath.Join(configDirectory, "config.json")
}

View File

@@ -0,0 +1,191 @@
package main
import (
"flag"
"fmt"
"github.com/gookit/config/v2"
"github.com/gookit/slog"
"github.com/kardianos/service"
agentgo "oneuptime-InfrastructureAgent-go"
"os"
)
type program struct {
exit chan struct{}
agent *agentgo.Agent
config *configFile
}
func (p *program) Start(s service.Service) error {
if service.Interactive() {
slog.Info("Running in terminal.")
} else {
slog.Info("Running under service manager.")
}
p.exit = make(chan struct{})
// Start should not block. Do the actual work async.
go p.run()
return nil
}
func (p *program) run() {
p.agent = agentgo.NewAgent(p.config.SecretKey, p.config.OneUptimeURL)
p.agent.Start()
if service.Interactive() {
slog.Info("Running in terminal.")
agentgo.NewShutdownHook().Close(func() {
slog.Info("Service Exiting...")
p.agent.Close()
})
} else {
slog.Info("Running under service manager.")
for {
select {
case _, ok := <-p.exit:
if !ok {
slog.Info("Service Exiting...")
p.agent.Close()
return
}
}
}
}
}
func (p *program) Stop(s service.Service) error {
close(p.exit)
return nil
}
func main() {
// Set up the configuration
config.WithOptions(config.WithTagName("json"))
cfg := newConfigFile()
// Set up the service
svcConfig := &service.Config{
Name: "oneuptime-infrastructure-agent",
DisplayName: "OneUptime Infrastructure Agent",
Description: "The OneUptime Infrastructure Agent (Golang Version) is a lightweight, open-source agent that collects system metrics and sends them to the OneUptime platform. It is designed to be easy to install and use, and to be extensible.",
Arguments: []string{"run"},
}
// Set up the program
prg := &program{
config: cfg,
}
// Create the service
s, err := service.New(prg, svcConfig)
if err != nil {
slog.Fatal(err)
os.Exit(2)
}
// Set up the logger
errs := make(chan error, 5)
l, err := s.Logger(errs)
if err != nil {
slog.Fatal(err)
os.Exit(2)
}
// Push the logger to the slog
logHandler := agentgo.NewServiceSysLogHandler(l)
slog.PushHandler(logHandler)
if len(os.Args) > 1 {
cmd := os.Args[1]
switch cmd {
case "install":
installFlags := flag.NewFlagSet("install", flag.ExitOnError)
secretKey := installFlags.String("secret-key", "", "Secret key (required)")
oneuptimeURL := installFlags.String("oneuptime-url", "", "Oneuptime endpoint root URL (required)")
err := installFlags.Parse(os.Args[2:])
if err != nil {
slog.Fatal(err)
os.Exit(2)
}
prg.config.SecretKey = *secretKey
prg.config.OneUptimeURL = *oneuptimeURL
if prg.config.SecretKey == "" || prg.config.OneUptimeURL == "" {
slog.Fatal("The --secret-key and --oneuptime-url flags are required for the 'install' command")
os.Exit(2)
}
// save configuration
err = prg.config.save(prg.config.SecretKey, prg.config.OneUptimeURL)
if err != nil {
slog.Fatal(err)
os.Exit(2)
}
// Install the service
if err := s.Install(); err != nil {
slog.Fatal("Failed to install service: ", err)
os.Exit(2)
}
fmt.Println("Service installed")
case "start":
err := prg.config.loadConfig()
if os.IsNotExist(err) {
slog.Fatal("Service configuration not found. Please install the service properly.")
os.Exit(2)
}
if err != nil {
slog.Fatal(err)
os.Exit(2)
}
if err != nil || prg.config.SecretKey == "" || prg.config.OneUptimeURL == "" {
slog.Fatal("Service configuration not found or is incomplete. Please install the service properly.")
os.Exit(2)
}
err = s.Start()
if err != nil {
slog.Fatal(err)
os.Exit(2)
}
slog.Info("Service Started")
case "run":
err := prg.config.loadConfig()
if os.IsNotExist(err) {
slog.Fatal("Service configuration not found. Please install the service properly.")
os.Exit(2)
}
if err != nil {
slog.Fatal(err)
os.Exit(2)
}
if err != nil || prg.config.SecretKey == "" || prg.config.OneUptimeURL == "" {
slog.Fatal("Service configuration not found or is incomplete. Please install the service properly.")
os.Exit(2)
}
err = s.Run()
if err != nil {
slog.Fatal(err)
os.Exit(2)
}
case "uninstall", "stop", "restart":
err := service.Control(s, cmd)
if err != nil {
slog.Fatal(err)
os.Exit(2)
}
if cmd == "uninstall" {
// remove configuration file
err := prg.config.removeConfigFile()
if err != nil {
slog.Fatal(err)
os.Exit(2)
}
slog.Info("Service Uninstalled")
}
if cmd == "stop" {
slog.Info("Service Stopped")
}
default:
slog.Error("Invalid command")
os.Exit(2)
}
} else {
fmt.Println("Usage: oneuptime-infrastructure-agent install | uninstall | start | stop | restart")
}
}

View File

@@ -0,0 +1,64 @@
package oneuptime_InfrastructureAgent_go
import (
"fmt"
"github.com/gookit/slog"
"github.com/shirou/gopsutil/v3/cpu"
"time"
)
func getCpuMetrics() *CPUMetrics {
//avg, err := load.Avg()
//if err != nil {
// slog.Error(err)
// return nil
//}
//
//numCpu, err := cpu.Counts(true)
//if err != nil {
// slog.Error(err)
// return nil
//}
//
//// Calculate CPU usage, which is the average load over the last minute divided by the number of CPUs
//cpuUsage := (avg.Load1 / float64(numCpu)) * 100
//trying new calculation method, more accurate
// Get CPU times at the start
startTimes, err := cpu.Times(false) // false to get the aggregate of all CPUs
if err != nil {
slog.Error(fmt.Errorf("error fetching initial CPU times: %v", err))
return nil
}
// Wait for a short interval (e.g., 1000 milliseconds)
time.Sleep(1000 * time.Millisecond)
// Get CPU times after the interval
endTimes, err := cpu.Times(false)
if err != nil {
slog.Error(fmt.Errorf("error fetching final CPU times: %v", err))
return nil
}
// Calculate the difference in total and idle times
totalDelta := totalCPUTime(endTimes[0]) - totalCPUTime(startTimes[0])
idleDelta := endTimes[0].Idle - startTimes[0].Idle
// Calculate the CPU usage percentage
if totalDelta == 0 {
slog.Error("totalDelta is 0")
return nil
}
cpuUsagePercent := (1 - idleDelta/totalDelta) * 100
return &CPUMetrics{
PercentUsed: cpuUsagePercent,
}
}
func totalCPUTime(times cpu.TimesStat) float64 {
return times.User + times.System + times.Idle + times.Nice +
times.Iowait + times.Irq + times.Softirq + times.Steal +
times.Guest + times.GuestNice
}

View File

@@ -0,0 +1,51 @@
package oneuptime_InfrastructureAgent_go
import (
"github.com/gookit/slog"
"github.com/shirou/gopsutil/v3/disk"
)
// getDiskMetrics retrieves disk metrics for a given path
func getDiskMetrics(path string) *BasicDiskMetrics {
usageStat, err := disk.Usage(path)
if err != nil {
slog.Error(err)
return nil
}
var percentUsed, percentFree float64
if usageStat.Total != 0 {
percentUsed = float64(usageStat.Used) / float64(usageStat.Total) * 100
percentFree = float64(usageStat.Free) / float64(usageStat.Total) * 100
}
metrics := &BasicDiskMetrics{
Total: usageStat.Total,
Free: usageStat.Free,
Used: usageStat.Used,
DiskPath: path,
PercentUsed: percentUsed,
PercentFree: percentFree,
}
return metrics
}
// listDiskMetrics lists disk metrics for all partitions
func listDiskMetrics() []*BasicDiskMetrics {
partitions, err := disk.Partitions(false) // set to true if you want all filesystems
if err != nil {
slog.Error(err)
return nil
}
var metricsList []*BasicDiskMetrics
for _, partition := range partitions {
metrics := getDiskMetrics(partition.Mountpoint)
if metrics == nil {
continue // Skip this partition on error
}
metricsList = append(metricsList, metrics)
}
return metricsList
}

View File

@@ -0,0 +1,39 @@
module oneuptime-InfrastructureAgent-go
go 1.22
require (
github.com/go-co-op/gocron/v2 v2.4.1
github.com/gookit/config/v2 v2.2.5
github.com/gookit/greq v0.3.0
github.com/gookit/slog v0.5.6
github.com/kardianos/service v1.2.2
github.com/shirou/gopsutil/v3 v3.24.4
)
replace gopkg.in/alecthomas/kingpin.v2 v2.4.0 => github.com/alecthomas/kingpin/v2 v2.4.0
require (
dario.cat/mergo v1.0.0 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gookit/color v1.5.4 // indirect
github.com/gookit/goutil v0.6.15 // indirect
github.com/gookit/gsr v0.1.0 // indirect
github.com/jonboulle/clockwork v0.4.0 // indirect
github.com/lufia/plan9stats v0.0.0-20240408141607-282e7b5d6b74 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
github.com/robfig/cron/v3 v3.0.1 // indirect
github.com/shoenig/go-m1cpu v0.1.6 // indirect
github.com/tklauser/go-sysconf v0.3.14 // indirect
github.com/tklauser/numcpus v0.8.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/term v0.15.0 // indirect
golang.org/x/text v0.15.0 // indirect
)

107
InfrastructureAgent/go.sum Normal file
View File

@@ -0,0 +1,107 @@
dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w=
github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg=
github.com/go-co-op/gocron/v2 v2.4.1 h1:jp+H58qqdEcZLY7sSTFAFOSThTW2Yp3aF5+5U4/NGpQ=
github.com/go-co-op/gocron/v2 v2.4.1/go.mod h1:ckPQw96ZuZLRUGu88vVpd9a6d9HakI14KWahFZtGvNw=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
github.com/goccy/go-yaml v1.11.2 h1:joq77SxuyIs9zzxEjgyLBugMQ9NEgTWxXfz2wVqwAaQ=
github.com/goccy/go-yaml v1.11.2/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0=
github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w=
github.com/gookit/config/v2 v2.2.5 h1:RECbYYbtherywmzn3LNeu9NA5ZqhD7MSKEMsJ7l+MpU=
github.com/gookit/config/v2 v2.2.5/go.mod h1:NeX+yiNYn6Ei10eJvCQFXuHEPIE/IPS8bqaFIsszzaM=
github.com/gookit/goutil v0.6.15 h1:mMQ0ElojNZoyPD0eVROk5QXJPh2uKR4g06slgPDF5Jo=
github.com/gookit/goutil v0.6.15/go.mod h1:qdKdYEHQdEtyH+4fNdQNZfJHhI0jUZzHxQVAV3DaMDY=
github.com/gookit/greq v0.3.0 h1:eOiKxdn0IYh4PHnfn0+svcXLyKwD2V/l87DUiZaIGIM=
github.com/gookit/greq v0.3.0/go.mod h1:z7U/ABiJZ3tiMZPJcmg7qmgMCRJ2LPclsqv4tDsAR2Q=
github.com/gookit/gsr v0.1.0 h1:0gadWaYGU4phMs0bma38t+Do5OZowRMEVlHv31p0Zig=
github.com/gookit/gsr v0.1.0/go.mod h1:7wv4Y4WCnil8+DlDYHBjidzrEzfHhXEoFjEA0pPPWpI=
github.com/gookit/ini/v2 v2.2.3 h1:nSbN+x9OfQPcMObTFP+XuHt8ev6ndv/fWWqxFhPMu2E=
github.com/gookit/ini/v2 v2.2.3/go.mod h1:Vu6p7P7xcfmb8KYu3L0ek8bqu/Im63N81q208SCCZY4=
github.com/gookit/slog v0.5.6 h1:fmh+7bfOK8CjidMCwE+M3S8G766oHJpT/1qdmXGALCI=
github.com/gookit/slog v0.5.6/go.mod h1:RfIwzoaQ8wZbKdcqG7+3EzbkMqcp2TUn3mcaSZAw2EQ=
github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4=
github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc=
github.com/kardianos/service v1.2.2 h1:ZvePhAHfvo0A7Mftk/tEzqEZ7Q4lgnR8sGz4xu1YX60=
github.com/kardianos/service v1.2.2/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/lufia/plan9stats v0.0.0-20240408141607-282e7b5d6b74 h1:1KuuSOy4ZNgW0KA2oYIngXVFhQcXxhLqCVK7cBcldkk=
github.com/lufia/plan9stats v0.0.0-20240408141607-282e7b5d6b74/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/shirou/gopsutil/v3 v3.24.4 h1:dEHgzZXt4LMNm+oYELpzl9YCqV65Yr/6SfrvgRBtXeU=
github.com/shirou/gopsutil/v3 v3.24.4/go.mod h1:lTd2mdiOspcqLgAnr9/nGi71NkeMpWKdmhuxm9GusH8=
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU=
github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY=
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
github.com/tklauser/numcpus v0.8.0 h1:Mx4Wwe/FjZLeQsK/6kt2EOepwwSl7SmJrK5bV/dXYgY=
github.com/tklauser/numcpus v0.8.0/go.mod h1:ZJZlAY+dmR4eut8epnzf0u/VwodKmryxR8txiloSqBE=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f h1:99ci1mjWVBWwJiEKYY6jWa4d2nTQVIEhZIptnrVb1XY=
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -0,0 +1,77 @@
#!/bin/sh
set -e
usage() {
echo "Usage: $0 [-b bindir] [-d]"
echo " -b sets the directory for the binary installation, default is ./bin"
echo " -d enables debug mode"
exit 1
}
# Default parameters
BINDIR=/usr/bin
DEBUG=0
# Parse command-line options
while getopts "b:d" opt; do
case ${opt} in
b )
BINDIR=$OPTARG
;;
d )
set -x
DEBUG=1
;;
\? )
usage
;;
esac
done
echo "Installing to ${BINDIR}"
mkdir -p "${BINDIR}"
# Detect platform and architecture
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
ARCH=$(uname -m)
case $ARCH in
x86_64)
ARCH=amd64
;;
aarch64)
ARCH=arm64
;;
*arm*)
ARCH=arm
;;
*)
echo "Architecture $ARCH is not supported"
exit 1
;;
esac
# Fetch the latest release tag from GitHub
REPO="anxuanzi/oneuptime-infrastructure-agent-go"
API_URL="https://api.github.com/repos/${REPO}/releases/latest"
TAG=$(curl -s ${API_URL} | grep '"tag_name":' | sed -E 's/.*"tag_name": "([^"]+)".*/\1/')
if [ "$TAG" = "" ]; then
echo "Failed to find the latest release. Please check your internet connection or GitHub API limits."
exit 1
fi
echo "Fetching the latest release: $TAG"
# Construct the URL for the binary release
URL="https://github.com/${REPO}/releases/download/${TAG}/oneuptime-infrastructure-agent_${OS}_${ARCH}.tar.gz"
# Download and extract the binary
curl -sL "${URL}" | tar xz -C "${BINDIR}"
# Check if the binary is executable
if [ ! -x "${BINDIR}/oneuptime-infrastructure-agent" ]; then
echo "Failed to install oneuptime-infrastructure-agent"
exit 1
fi
echo "oneuptime-infrastructure-agent installed successfully to ${BINDIR}"

View File

@@ -0,0 +1,21 @@
package oneuptime_InfrastructureAgent_go
import (
"github.com/gookit/slog"
"github.com/shirou/gopsutil/v3/mem"
)
func getMemoryMetrics() *MemoryMetrics {
memoryInfo, err := mem.VirtualMemory()
if err != nil {
slog.Error("Error while fetching memory metrics: ", err)
return nil
}
return &MemoryMetrics{
Total: memoryInfo.Total,
Free: memoryInfo.Free,
Used: memoryInfo.Used,
PercentUsed: memoryInfo.UsedPercent,
PercentFree: 100 - memoryInfo.UsedPercent,
}
}

View File

@@ -0,0 +1,42 @@
package oneuptime_InfrastructureAgent_go
type MemoryMetrics struct {
Total uint64 `json:"total"`
Free uint64 `json:"free"`
Used uint64 `json:"used"`
PercentUsed float64 `json:"percentUsed"`
PercentFree float64 `json:"percentFree"`
}
type CPUMetrics struct {
PercentUsed float64 `json:"percentUsed"`
}
type BasicDiskMetrics struct {
Total uint64 `json:"total"`
Free uint64 `json:"free"`
Used uint64 `json:"used"`
DiskPath string `json:"diskPath"`
PercentUsed float64 `json:"percentUsed"`
PercentFree float64 `json:"percentFree"`
}
type BasicInfrastructureMetrics struct {
CpuMetrics *CPUMetrics `json:"cpuMetrics"`
MemoryMetrics *MemoryMetrics `json:"memoryMetrics"`
DiskMetrics []*BasicDiskMetrics `json:"diskMetrics"`
}
type ServerProcess struct {
Pid int32 `json:"pid"`
Name string `json:"name"`
Command string `json:"command"`
}
type ServerMonitorReport struct {
SecretKey string `json:"secretKey"`
BasicInfrastructureMetrics *BasicInfrastructureMetrics `json:"basicInfrastructureMetrics"`
RequestReceivedAt string `json:"requestReceivedAt"`
OnlyCheckRequestReceivedAt bool `json:"onlyCheckRequestReceivedAt"`
Processes []*ServerProcess `json:"processes"`
}

View File

@@ -1,8 +0,0 @@
{
"watch": ["./","../Common", "../CommonServer", "../Model"],
"ext": "ts,json,tsx,env,js,jsx,hbs",
"ignore": [
"greenlock.d/*"
],
"exec": "node --inspect=0.0.0.0:9229 --require ts-node/register Index.ts"
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,42 +0,0 @@
{
"name": "@oneuptime/infrastructure-agent",
"version": "1.0.0",
"description": "",
"scripts": {
"start": "npx tsx Index.ts",
"build": "esbuild Index.ts --bundle --platform=node --outfile=./build/Index.js --loader:.node=file",
"compile": "tsc",
"clear-modules": "rm -rf node_modules && rm package-lock.json && npm install",
"dev": "npx nodemon",
"audit": "npm audit --audit-level=low",
"dep-check": "npm install -g depcheck && depcheck ./ --skip-missing=true",
"test": "rm -rf build && jest --detectOpenHandles",
"coverage": "jest --detectOpenHandles --coverage",
"publish-package": "export PACKAGE_NAME=@oneuptime/infrastructure-agent && bash ../Scripts/NPM/PublishPackage.sh"
},
"author": "OneUptime <hello@oneuptime.com> (https://oneuptime.com/)",
"license": "Apache-2.0",
"dependencies": {
"@types/jest": "^29.5.11",
"@types/node": "^17.0.31",
"@types/node-cron": "^3.0.11",
"@types/yargs": "^17.0.32",
"axios": "^1.6.8",
"diskusage": "^1.2.0",
"drivelist": "^11.2.2",
"esbuild": "^0.20.1",
"node-cron": "^3.0.3",
"ps-list": "^8.1.1",
"typescript": "^5.4.2",
"yargs": "^17.7.2",
"tsx": "^4.7.1"
},
"bin": {
"oneuptime-infrastructure-agent": "./Index.ts"
},
"devDependencies": {
"jest": "^28.1.0",
"nodemon": "^2.0.20"
}
}

View File

@@ -0,0 +1,38 @@
package oneuptime_InfrastructureAgent_go
import (
"github.com/gookit/slog"
"github.com/shirou/gopsutil/v3/process"
)
// getServerProcesses retrieves the list of server processes
func getServerProcesses() []*ServerProcess {
var serverProcesses []*ServerProcess
// Fetch all processes
processList, err := process.Processes()
if err != nil {
slog.Error("Failed to fetch process list", err)
return nil
}
// Iterate over all processes and collect details
for _, p := range processList {
name, err := p.Name()
if err != nil {
continue // skip processes where details cannot be retrieved
}
cmdline, err := p.Cmdline()
if err != nil {
continue
}
serverProcesses = append(serverProcesses, &ServerProcess{
Pid: p.Pid,
Name: name,
Command: cmdline,
})
}
return serverProcesses
}

View File

@@ -1,4 +0,0 @@
{
"main": "./build/Index.js",
"output": "sea-prep.blob"
}

View File

@@ -0,0 +1,52 @@
package oneuptime_InfrastructureAgent_go
import (
"os"
"os/signal"
"syscall"
)
// thanks to https://github.com/xinliangnote/go-gin-api
var _ Hook = (*hook)(nil)
// Hook a graceful shutdown hook, default with signals of SIGINT and SIGTERM
type Hook interface {
// WithSignals add more signals into hook
WithSignals(signals ...syscall.Signal) Hook
// Close register shutdown handles
Close(funcs ...func())
}
type hook struct {
ctx chan os.Signal
}
// NewHook create a Hook instance
func NewShutdownHook() Hook {
hook := &hook{
ctx: make(chan os.Signal, 1),
}
return hook.WithSignals(syscall.SIGINT, syscall.SIGTERM)
}
func (h *hook) WithSignals(signals ...syscall.Signal) Hook {
for _, s := range signals {
signal.Notify(h.ctx, s)
}
return h
}
func (h *hook) Close(funcs ...func()) {
select {
case <-h.ctx:
}
signal.Stop(h.ctx)
for _, f := range funcs {
f()
}
}

View File

@@ -0,0 +1,38 @@
package oneuptime_InfrastructureAgent_go
import (
"github.com/gookit/slog"
"github.com/kardianos/service"
)
type ServiceSysLogHandler struct {
slog.LevelWithFormatter
systemServiceLogger service.Logger
}
func NewServiceSysLogHandler(serviceLogger service.Logger) *ServiceSysLogHandler {
return &ServiceSysLogHandler{
systemServiceLogger: serviceLogger,
}
}
func (s *ServiceSysLogHandler) Close() error {
return nil
}
func (s *ServiceSysLogHandler) Flush() error {
return nil
}
//func (s *ServiceSysLogHandler) IsHandling(level slog.Level) bool {
// //TODO implement me
// panic("implement me")
//}
func (s *ServiceSysLogHandler) Handle(record *slog.Record) error {
formattedLog, err := s.Formatter().Format(record)
if err != nil {
return err
}
return s.systemServiceLogger.Info(string(formattedLog))
}

View File

@@ -1,112 +0,0 @@
{
"ts-node": {
// these options are overrides used only by ts-node
// same as the --compilerOptions flag and the TS_NODE_COMPILER_OPTIONS environment variable
"compilerOptions": {
"module": "commonjs",
"resolveJsonModule": true,
}
},
"compilerOptions": {
/* Visit https://aka.ms/tsconfig.json to read more about this file */
/* Projects */
// "incremental": true, /* Enable incremental compilation */
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
// "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
/* Language and Environment */
"target": "es2017" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
"jsx": "react" /* Specify what JSX code is generated. */,
"experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
"emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */
// "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
/* Modules */
// "module": "es2022" /* Specify what module code is generated. */,
// "rootDir": "./", /* Specify the root folder within your source files. */
"moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
"typeRoots": [
"./node_modules/@types"
], /* Specify multiple folders that act like `./node_modules/@types`. */
"types": ["node", "jest"], /* Specify type package names to be included without being referenced in a source file. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
// "resolveJsonModule": true, /* Enable importing .json files */
// "noResolve": true, /* Disallow `import`s, `require`s or `<reference>`s from expanding the number of files TypeScript should add to a project. */
/* JavaScript Support */
// "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */
/* Emit */
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
"sourceMap": true, /* Create source map files for emitted JavaScript files. */
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */
"outDir": "./build/dist", /* Specify an output folder for all emitted files. */
// "removeComments": true, /* Disable emitting comments. */
// "noEmit": true, /* Disable emitting files from a compilation. */
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
// "newLine": "crlf", /* Set the newline character for emitting files. */
// "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */
// "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
// "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
/* Interop Constraints */
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
"esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */,
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
/* Type Checking */
"strict": true /* Enable all strict type-checking options. */,
"noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */
"strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */
"strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
"strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */
"strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
"noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */
"useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */
"alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
"noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */
"noUnusedParameters": true, /* Raise an error when a function parameter isn't read */
"exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
"noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
"noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
"noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
"noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
"noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
/* Completeness */
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
"skipLibCheck": true, /* Skip type checking all .d.ts files. */
"resolveJsonModule": true
}
}