Skip to content

Commit

Permalink
feat: simplified node installation & docs
Browse files Browse the repository at this point in the history
  • Loading branch information
robot9706 committed Oct 16, 2023
1 parent a90cbd5 commit 1bf7ce4
Show file tree
Hide file tree
Showing 19 changed files with 99 additions and 250 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,14 @@ Ensure data persistence by using Docker volumes to store Darklens data.
2. Enter a name for your node and click Save
- This'll be the name of the agent running as a container on your node
3. On the right side of the screen, select whether you'd like to install the agent with a Shell (UNIX) or a PowerShell (Windows) script

> Note: Shell scripts might not work on Windows using Git Bash.
4. Generate the script and copy & paste it into Shell or PowerShell. Press enter to install the agent
5. When node status turns green, you're ready to use darklens

> Note: Agents connect to the host defined in their JWT token (`GRPC_TOKEN` environment), by default the `AGENT_ADDRESS` backend environment variable is used, but users can override this value on the UI.
## Development

1. Setup backend
Expand Down
11 changes: 10 additions & 1 deletion web/backend/.env.example
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
NODE_ENV=development

# Database access path
DATABASE=file:dev.db

# Domain used to sign and verify auth tokens
PUBLIC_URL=http://localhost:8000

# Disable authorization for the UI
DISABLE_AUTH=true

# Port where the HTTP server is hosted
HTTP_API_PORT=3100

# Port where the gRPC server is hosted for agents
GRPC_AGENT_PORT=5000

# The address used for the issuer of agent JWT tokens, this is the address where agents will connect to
AGENT_ADDRESS=http://host.docker.internal:5000

# Secret string used to sign JWT tokens
JWT_SECRET=jwt-secret-token
DISABLE_AUTH=true

# Possible values: trace, debug, info, warn, error, and fatal
# The settings above come in a hierarchic order
Expand Down
19 changes: 0 additions & 19 deletions web/backend/assets/install-script/install-docker.ps1.hbr
Original file line number Diff line number Diff line change
@@ -1,25 +1,6 @@
Set-PSDebug -strict
Set-StrictMode -version latest
$ErrorActionPreference = 'Stop'

try { docker stop '{{name}}' }
catch { Write-Output "{{name}} couldn't be found or stopped" }
finally {
try { docker rm '{{name}}' }
catch { Write-Output "{{name}} couldn't be found or removed" }
}

If ( -not ${{disableForcePull}} ) {
docker pull ghcr.io/dyrector-io/darklens/agent:{{agentImageTag}}
}

docker run `
--restart on-failure `
{{#if network}}
--network {{networkName}} `
{{/if}}
-e GRPC_TOKEN='{{token}}' `
-e HOST_DOCKER_SOCK_PATH=//var/run/docker.sock `
--add-host=host.docker.internal:host-gateway `
--name '{{name}}' `
-v //var/run/docker.sock:/var/run/docker.sock `
Expand Down
133 changes: 7 additions & 126 deletions web/backend/assets/install-script/install-docker.sh.hbr
Original file line number Diff line number Diff line change
@@ -1,126 +1,7 @@
#!/bin/sh

set -eu

case $(uname) in
Linux*)
ROOTLESS="${ROOTLESS:-false}"
;;
*)
ROOTLESS="${ROOTLESS:-true}"
;;
esac

if [ "$ROOTLESS" = "false" ]; then
if [ "$(id -u)" -ne 0 ]; then
echo "Installation process needs root privileges" 1>&2
# This will quit the non-root script & restart the script as root
exec sudo -s "$0"
fi
fi

case $(uname) in
Darwin*)
PLATFORM="OSX"
;;
Linux*)
PLATFORM="LINUX"
;;
MINGW*)
PLATFORM="WINDOWS"
if [ -n "${MSYS_NO_PATHCONV+x}" ]; then
ORIGINAL_PATHCONV_CONFIG=$MSYS_NO_PATHCONV
fi

export MSYS_NO_PATHCONV=1
HOST_DOCKER_SOCK_PATH="${HOST_DOCKER_SOCK_PATH:-//var/run/docker.sock}"
;;
*)
echo "Not Supported OS"
exit 1
;;
esac

set_environment() {
if [ -z "${CRI_EXECUTABLE:-}" ]; then
if ! command -v docker >/dev/null 2>&1; then
if ! command -v podman >/dev/null 2>&1; then
echo "Docker is required, make sure it is installed and available in PATH!"
exit 1
else
CRI_EXECUTABLE="podman"
fi
else
CRI_EXECUTABLE="docker"
fi
fi

if [ -z "${HOST_DOCKER_SOCK_PATH:-}" ]; then
if [ -z "${DOCKER_HOST:-}" ]; then
HOST_DOCKER_SOCK_PATH="/var/run/docker.sock"
else
if [ $(echo "$DOCKER_HOST" | cut -b -7) = "unix://" ]; then
HOST_DOCKER_SOCK_PATH=$(echo "$DOCKER_HOST" | cut -b 7-)
else
echo "Invalid DOCKER_HOST variable please set HOST_DOCKER_SOCK_PATH if your socket is in a custom location otherwise unset DOCKER_HOST!"
exit 1
fi
fi
fi
}

agent_clean() {
if [ -n "$($CRI_EXECUTABLE container list --filter name=^{{name}}$ --filter=status=running --filter=status=restarting --filter=status=paused --format '\{{ .Names }}' 2>/dev/null)" ]; then
set +e
echo "Stopping existing dyrector.io agent ({{name}})..."
$CRI_EXECUTABLE stop '{{name}}'
if ! $CRI_EXECUTABLE stop '{{name}}'; then
set -e
$CRI_EXECUTABLE kill '{{name}}'
fi
set -e
fi

if [ -n "$($CRI_EXECUTABLE container list --filter name=^{{name}}$ --filter=status=exited --filter=status=created --filter=status=dead --format '\{{ .Names }}' 2>/dev/null)" ]; then
set +e
echo "Removing existing dyrector.io agent ({{name}})..."
$CRI_EXECUTABLE rm '{{name}}'
if $CRI_EXECUTABLE rm '{{name}}'; then
set -e
$CRI_EXECUTABLE rm -f '{{name}}'
fi
set -e
fi
}

agent_install() {
echo "Installing Darklens Agent ({{name}})..."

if ! {{disableForcePull}}; then
$CRI_EXECUTABLE pull ghcr.io/dyrector-io/darklens/agent:{{agentImageTag}}
fi

$CRI_EXECUTABLE run \
--restart on-failure \
{{#if network}}
--network {{networkName}} \
{{/if}}
-e GRPC_TOKEN='{{token}}' \
-e HOST_DOCKER_SOCK_PATH="$HOST_DOCKER_SOCK_PATH" \
--add-host=host.docker.internal:host-gateway \
--name '{{name}}' \
-v "$HOST_DOCKER_SOCK_PATH":/var/run/docker.sock \
-d ghcr.io/dyrector-io/darklens/agent:{{agentImageTag}}

if [ -z "${ORIGINAL_PATHCONV_CONFIG+x}" ]; then
unset MSYS_NO_PATHCONV
else
export MSYS_NO_PATHCONV="$ORIGINAL_PATHCONV_CONFIG"
fi
}

set_environment

agent_clean

agent_install
docker run \
--restart on-failure \
-e GRPC_TOKEN='{{token}}' \
--add-host=host.docker.internal:host-gateway \
--name '{{name}}' \
-v /var/run/docker.sock:/var/run/docker.sock \
-d ghcr.io/dyrector-io/darklens/agent:{{agentImageTag}}
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,8 @@ CREATE TABLE "Node" (
"icon" TEXT,
"address" TEXT,
"connectedAt" DATETIME,
"disconnectedAt" DATETIME
);

-- CreateTable
CREATE TABLE "NodeToken" (
"nodeId" TEXT NOT NULL PRIMARY KEY,
"nonce" TEXT NOT NULL,
CONSTRAINT "NodeToken_nodeId_fkey" FOREIGN KEY ("nodeId") REFERENCES "Node" ("id") ON DELETE CASCADE ON UPDATE CASCADE
"disconnectedAt" DATETIME,
"tokenNonce" TEXT
);

-- CreateTable
Expand Down
3 changes: 3 additions & 0 deletions web/backend/prisma/migrations/migration_lock.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Please do not edit this file manually
# It should be added in your version-control system (i.e. Git)
provider = "sqlite"
9 changes: 1 addition & 8 deletions web/backend/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,13 @@ model Node {
address String?
connectedAt DateTime?
disconnectedAt DateTime?
tokenNonce String?
events NodeEvent[]
token NodeToken?
@@unique([name])
}

model NodeToken {
nodeId String @id @unique
nonce String
node Node @relation(fields: [nodeId], references: [id], onDelete: Cascade)
}

model NodeEvent {
id String @id @default(uuid())
nodeId String
Expand Down
21 changes: 10 additions & 11 deletions web/backend/src/app/agent/agent.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,23 +99,22 @@ export default class AgentService {
scriptType,
})

await this.prisma.node.update({
where: {
id: node.id,
},
data: {
tokenNonce: token.nonce,
},
})

this.installers.set(node.id, installer)

return installer
}

async discardInstaller(nodeId: string): Promise<Empty> {
if (!this.installers.has(nodeId)) {
throw new CruxNotFoundException({
message: 'Installer not found',
property: 'installer',
value: nodeId,
})
}

discardInstaller(nodeId: string) {
this.installers.delete(nodeId)

return Empty
}

async completeInstaller(installer: AgentInstaller) {
Expand Down
24 changes: 21 additions & 3 deletions web/backend/src/app/agent/guards/agent.auth.guard.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,35 @@
import { Metadata } from '@grpc/grpc-js'
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common'
import { JwtService } from '@nestjs/jwt'
import PrismaService from 'src/services/prisma.service'
import GrpcNodeConnection, { NodeGrpcCall } from 'src/shared/grpc-node-connection'

@Injectable()
export default class AgentAuthGuard implements CanActivate {
constructor(private jwt: JwtService) {}
constructor(
private jwt: JwtService,
private prisma: PrismaService,
) {}

canActivate(context: ExecutionContext): boolean {
async canActivate(context: ExecutionContext): Promise<boolean> {
const metadata = context.getArgByIndex<Metadata>(1)
const call = context.getArgByIndex<NodeGrpcCall>(2)

const connection = new GrpcNodeConnection(metadata, call)
return connection.verify(this.jwt)
if (!connection.verify(this.jwt)) {
return false
}

const node = await this.prisma.node.findFirst({
where: {
id: connection.nodeId,
tokenNonce: connection.tokenNonce,
},
})
if (!node) {
return false
}

return true
}
}
3 changes: 0 additions & 3 deletions web/backend/src/app/node/node.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,6 @@ export class NodeDto extends BasicNodeDto {
}

export class NodeInstallDto {
@IsString()
command: string

@IsString()
script: string

Expand Down
6 changes: 2 additions & 4 deletions web/backend/src/app/node/node.mapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { Inject, Injectable, forwardRef } from '@nestjs/common'
import { Node } from '@prisma/client'
import { AgentConnectionMessage } from 'src/domain/agent'
import AgentInstaller from 'src/domain/agent-installer'
import { NodeWithToken } from 'src/domain/node'
import { fromTimestamp } from 'src/domain/utils'
import {
ContainerInspectMessage,
Expand Down Expand Up @@ -69,22 +68,21 @@ export default class NodeMapper {
}
}

detailsToDto(node: NodeWithToken): NodeDetailsDto {
detailsToDto(node: Node): NodeDetailsDto {
const installer = this.agentService.getInstallerByNodeId(node.id)

const agent = this.agentService.getById(node.id)

return {
...this.toDto(node),
hasToken: !!node.token,
hasToken: !!node.tokenNonce,
install: installer ? this.installerToDto(installer) : null,
updatable: agent && (agent.outdated || !this.agentService.agentVersionIsUpToDate(agent.version)),
}
}

installerToDto(installer: AgentInstaller): NodeInstallDto {
return {
command: installer.getCommand(),
script: installer.getScript(),
expireAt: installer.expireAt,
}
Expand Down
Loading

0 comments on commit 1bf7ce4

Please sign in to comment.