mirror of
https://github.com/OneUptime/oneuptime.git
synced 2026-04-06 00:32:12 +02:00
♻️ remove the nodejs version agent, rewrite in Golang
This commit is contained in:
166
InfrastructureAgent/.gitignore
vendored
Normal file
166
InfrastructureAgent/.gitignore
vendored
Normal 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
|
||||
45
InfrastructureAgent/.goreleaser.yaml
Normal file
45
InfrastructureAgent/.goreleaser.yaml
Normal 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:"
|
||||
@@ -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 }}
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
@@ -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
201
InfrastructureAgent/LICENSE
Normal 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
52
InfrastructureAgent/README.md
Executable file → Normal 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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
@@ -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>;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 [];
|
||||
}
|
||||
}
|
||||
}
|
||||
146
InfrastructureAgent/agent.go
Normal file
146
InfrastructureAgent/agent.go
Normal 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
|
||||
}
|
||||
128
InfrastructureAgent/cmd/config.go
Normal file
128
InfrastructureAgent/cmd/config.go
Normal 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")
|
||||
}
|
||||
191
InfrastructureAgent/cmd/main.go
Normal file
191
InfrastructureAgent/cmd/main.go
Normal 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")
|
||||
}
|
||||
}
|
||||
64
InfrastructureAgent/cpu.go
Normal file
64
InfrastructureAgent/cpu.go
Normal 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
|
||||
}
|
||||
51
InfrastructureAgent/disk.go
Normal file
51
InfrastructureAgent/disk.go
Normal 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
|
||||
}
|
||||
39
InfrastructureAgent/go.mod
Normal file
39
InfrastructureAgent/go.mod
Normal 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
107
InfrastructureAgent/go.sum
Normal 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=
|
||||
77
InfrastructureAgent/install.sh
Normal file
77
InfrastructureAgent/install.sh
Normal 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}"
|
||||
21
InfrastructureAgent/memory.go
Normal file
21
InfrastructureAgent/memory.go
Normal 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,
|
||||
}
|
||||
}
|
||||
42
InfrastructureAgent/model.go
Normal file
42
InfrastructureAgent/model.go
Normal 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"`
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
6554
InfrastructureAgent/package-lock.json
generated
6554
InfrastructureAgent/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -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"
|
||||
|
||||
}
|
||||
}
|
||||
38
InfrastructureAgent/procs.go
Normal file
38
InfrastructureAgent/procs.go
Normal 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
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"main": "./build/Index.js",
|
||||
"output": "sea-prep.blob"
|
||||
}
|
||||
52
InfrastructureAgent/shutdown.go
Normal file
52
InfrastructureAgent/shutdown.go
Normal 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()
|
||||
}
|
||||
}
|
||||
38
InfrastructureAgent/slog_sys_handler.go
Normal file
38
InfrastructureAgent/slog_sys_handler.go
Normal 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))
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user