mirror of
https://github.com/MizuchiLabs/mantrae.git
synced 2025-12-21 06:10:04 -06:00
prepare for agent mode
This commit is contained in:
69
.github/workflows/docker-build.yml
vendored
69
.github/workflows/docker-build.yml
vendored
@@ -1,69 +0,0 @@
|
|||||||
# Disable for now
|
|
||||||
# name: Docker Build
|
|
||||||
#
|
|
||||||
# on:
|
|
||||||
# push:
|
|
||||||
# branches:
|
|
||||||
# - main
|
|
||||||
# tags:
|
|
||||||
# - 'v*'
|
|
||||||
# pull_request:
|
|
||||||
# branches:
|
|
||||||
# - main
|
|
||||||
#
|
|
||||||
# jobs:
|
|
||||||
# build:
|
|
||||||
# runs-on: ubuntu-latest
|
|
||||||
#
|
|
||||||
# permissions:
|
|
||||||
# contents: read
|
|
||||||
# packages: write
|
|
||||||
# attestations: write
|
|
||||||
# id-token: write
|
|
||||||
#
|
|
||||||
# steps:
|
|
||||||
# - name: Checkout
|
|
||||||
# uses: actions/checkout@v4
|
|
||||||
#
|
|
||||||
# - name: Set up Node
|
|
||||||
# uses: actions/setup-node@v4
|
|
||||||
# with:
|
|
||||||
# node-version: 20.x
|
|
||||||
#
|
|
||||||
# - name: Set up QEMU
|
|
||||||
# uses: docker/setup-qemu-action@v3
|
|
||||||
#
|
|
||||||
# - name: Set up Docker Buildx
|
|
||||||
# uses: docker/setup-buildx-action@v3
|
|
||||||
#
|
|
||||||
# - name: Install dependencies
|
|
||||||
# run: |
|
|
||||||
# cd web
|
|
||||||
# npm install
|
|
||||||
# npm run build
|
|
||||||
#
|
|
||||||
# - name: Login to GitHub Container Registry
|
|
||||||
# uses: docker/login-action@v3
|
|
||||||
# with:
|
|
||||||
# registry: ghcr.io
|
|
||||||
# username: ${{ github.actor }}
|
|
||||||
# password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
#
|
|
||||||
# - name: Extract metadata (tags, labels) for Docker
|
|
||||||
# id: meta
|
|
||||||
# uses: docker/metadata-action@v5
|
|
||||||
# with:
|
|
||||||
# images: |
|
|
||||||
# ghcr.io/${{ github.repository }}
|
|
||||||
# tags: |
|
|
||||||
# type=raw,value=latest,enable={{is_default_branch}}
|
|
||||||
# type=semver,pattern={{version}}
|
|
||||||
#
|
|
||||||
# - name: Build and push
|
|
||||||
# uses: docker/build-push-action@v6
|
|
||||||
# with:
|
|
||||||
# context: .
|
|
||||||
# platforms: linux/amd64
|
|
||||||
# push: ${{ github.event_name != 'pull_request' }}
|
|
||||||
# tags: ${{ steps.meta.outputs.tags }}
|
|
||||||
# labels: ${{ steps.meta.outputs.labels }}
|
|
||||||
@@ -13,14 +13,14 @@ steps:
|
|||||||
- pnpm install
|
- pnpm install
|
||||||
- pnpm build
|
- pnpm build
|
||||||
|
|
||||||
# - name: backend-audit
|
- name: backend-audit
|
||||||
# image: golang:latest
|
image: golang:latest
|
||||||
# commands:
|
commands:
|
||||||
# - go fmt ./...
|
- go fmt ./...
|
||||||
# - go vet ./...
|
- go vet ./...
|
||||||
# - go mod tidy
|
- go mod tidy
|
||||||
# - go mod verify
|
- go mod verify
|
||||||
# - go test ./...
|
- go test ./...
|
||||||
|
|
||||||
- name: container-build
|
- name: container-build
|
||||||
image: woodpeckerci/plugin-docker-buildx
|
image: woodpeckerci/plugin-docker-buildx
|
||||||
|
|||||||
206
agent/client/client.go
Normal file
206
agent/client/client.go
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"log"
|
||||||
|
"log/slog"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"slices"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"connectrpc.com/connect"
|
||||||
|
agentv1 "github.com/MizuchiLabs/mantrae/agent/proto/gen/agent/v1"
|
||||||
|
"github.com/MizuchiLabs/mantrae/agent/proto/gen/agent/v1/agentv1connect"
|
||||||
|
"github.com/MizuchiLabs/mantrae/pkg/util"
|
||||||
|
"github.com/docker/docker/api/types/container"
|
||||||
|
"github.com/docker/docker/client"
|
||||||
|
"google.golang.org/protobuf/types/known/timestamppb"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Client(quit chan os.Signal) {
|
||||||
|
token := LoadToken()
|
||||||
|
|
||||||
|
// Decode the JWT to get auth token and server URL
|
||||||
|
claims, err := util.DecodeJWT(token)
|
||||||
|
if err != nil {
|
||||||
|
DeleteToken()
|
||||||
|
log.Fatalf("Failed to decode JWT: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new client instance
|
||||||
|
client := agentv1connect.NewAgentServiceClient(
|
||||||
|
http.DefaultClient,
|
||||||
|
claims.ServerURL,
|
||||||
|
connect.WithGRPC(),
|
||||||
|
)
|
||||||
|
slog.Info("Connected to", "server", claims.ServerURL)
|
||||||
|
|
||||||
|
// Start a goroutine for sending container data
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
// Send machine/container info
|
||||||
|
if _, err := client.GetContainer(context.Background(), sendContainer(claims.Secret)); err != nil {
|
||||||
|
slog.Error(
|
||||||
|
"Failed to send container info",
|
||||||
|
"server",
|
||||||
|
claims.ServerURL,
|
||||||
|
"error",
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// Wait 10 seconds before sending the next container info
|
||||||
|
time.Sleep(10 * time.Second)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Start a separate goroutine for refreshing the token
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
// Refresh token
|
||||||
|
tokenRequest := connect.NewRequest(&agentv1.RefreshTokenRequest{Token: token})
|
||||||
|
tokenRequest.Header().Set("Authorization", "Bearer "+claims.Secret)
|
||||||
|
newToken, err := client.RefreshToken(context.Background(), tokenRequest)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("Failed to refresh token", "server", claims.ServerURL, "error", err)
|
||||||
|
} else {
|
||||||
|
SaveToken(newToken.Msg.Token)
|
||||||
|
token = newToken.Msg.Token
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(1 * time.Hour)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Wait for the main loop to finish
|
||||||
|
<-quit
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadToken() string {
|
||||||
|
token, err := os.ReadFile("token")
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("Failed to read token", "error", err)
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(string(token))
|
||||||
|
}
|
||||||
|
|
||||||
|
func SaveToken(token string) {
|
||||||
|
err := os.WriteFile("token", []byte(token), 0644)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("Failed to write token", "error", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteToken() {
|
||||||
|
err := os.Remove("token")
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("Failed to delete token", "error", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sendContainer creates a GetContainerRequest with information about the local machine
|
||||||
|
func sendContainer(secret string) *connect.Request[agentv1.GetContainerRequest] {
|
||||||
|
var request agentv1.GetContainerRequest
|
||||||
|
|
||||||
|
// Get machine ID
|
||||||
|
machineID, err := os.ReadFile("/etc/machine-id")
|
||||||
|
if err != nil {
|
||||||
|
request.Id = "unknown"
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(machineID) > 0 {
|
||||||
|
request.Id = strings.TrimSpace(string(machineID))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get hostname
|
||||||
|
hostname, err := os.Hostname()
|
||||||
|
if err != nil {
|
||||||
|
request.Hostname = "unknown"
|
||||||
|
}
|
||||||
|
request.Hostname = hostname
|
||||||
|
|
||||||
|
request.PublicIp, err = util.GetPublicIP()
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("Failed to get public IP", "error", err)
|
||||||
|
}
|
||||||
|
request.PrivateIps, err = util.GetPrivateIP()
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("Failed to get local IP", "error", err)
|
||||||
|
}
|
||||||
|
request.Containers, err = getContainers()
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("Failed to get containers", "error", err)
|
||||||
|
}
|
||||||
|
request.LastSeen = timestamppb.New(time.Now())
|
||||||
|
|
||||||
|
req := connect.NewRequest(&request)
|
||||||
|
req.Header().Set("authorization", "Bearer "+secret)
|
||||||
|
return req
|
||||||
|
}
|
||||||
|
|
||||||
|
// getContainers retrieves all containers and their info on the local machine
|
||||||
|
func getContainers() ([]*agentv1.Container, error) {
|
||||||
|
// Create a new Docker client
|
||||||
|
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("failed to create Docker client")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all containers
|
||||||
|
containers, err := cli.ContainerList(context.Background(), container.ListOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("failed to list containers")
|
||||||
|
}
|
||||||
|
|
||||||
|
var result []*agentv1.Container
|
||||||
|
|
||||||
|
// Iterate over each container and populate the Container struct
|
||||||
|
for _, c := range containers {
|
||||||
|
// Retrieve the container details
|
||||||
|
containerJSON, err := cli.ContainerInspect(context.Background(), c.ID)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("Failed to inspect container", "container", c.ID, "error", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Populate PortInfo
|
||||||
|
var ports []int32
|
||||||
|
for _, portmap := range containerJSON.NetworkSettings.Ports {
|
||||||
|
for _, binding := range portmap {
|
||||||
|
port, err := strconv.ParseInt(binding.HostPort, 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("Failed to parse port", "port", port, "error", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ports = append(ports, int32(port))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove duplicates
|
||||||
|
slices.Sort(ports)
|
||||||
|
ports = slices.Compact(ports)
|
||||||
|
|
||||||
|
created, err := time.Parse(time.RFC3339, containerJSON.Created)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("Failed to parse created time", "time", containerJSON.Created, "error", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Populate the Container struct
|
||||||
|
container := &agentv1.Container{
|
||||||
|
Id: c.ID,
|
||||||
|
Name: c.Names[0], // Take the first name if multiple exist
|
||||||
|
Labels: containerJSON.Config.Labels,
|
||||||
|
Image: containerJSON.Config.Image,
|
||||||
|
Ports: ports,
|
||||||
|
Status: containerJSON.State.Status,
|
||||||
|
Created: timestamppb.New(created),
|
||||||
|
}
|
||||||
|
|
||||||
|
result = append(result, container)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
48
agent/cmd/main.go
Normal file
48
agent/cmd/main.go
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"log"
|
||||||
|
"log/slog"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/MizuchiLabs/mantrae/agent/client"
|
||||||
|
"github.com/lmittmann/tint"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Set up global logger
|
||||||
|
func init() {
|
||||||
|
logger := slog.New(tint.NewHandler(os.Stdout, nil))
|
||||||
|
slog.SetDefault(logger)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
token := flag.String("token", "", "Authentication token (required)")
|
||||||
|
// update := flag.Bool("update", false, "Update to latest version")
|
||||||
|
version := flag.Bool("version", false, "Show version")
|
||||||
|
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
if *token == "" {
|
||||||
|
*token = client.LoadToken()
|
||||||
|
if len(*token) == 0 {
|
||||||
|
slog.Error("missing token")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
client.SaveToken(*token)
|
||||||
|
}
|
||||||
|
|
||||||
|
if *version {
|
||||||
|
log.Println("v0.0.1")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
quit := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
|
||||||
|
slog.Info("Starting agent...")
|
||||||
|
client.Client(quit)
|
||||||
|
}
|
||||||
37
agent/proto/agent/v1/agent.proto
Normal file
37
agent/proto/agent/v1/agent.proto
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package agent.v1;
|
||||||
|
|
||||||
|
import "google/protobuf/timestamp.proto";
|
||||||
|
|
||||||
|
service AgentService {
|
||||||
|
rpc GetContainer(GetContainerRequest) returns (GetContainerResponse);
|
||||||
|
rpc RefreshToken(RefreshTokenRequest) returns (RefreshTokenResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
message Container {
|
||||||
|
string id = 1;
|
||||||
|
string name = 2;
|
||||||
|
map<string, string> labels = 3;
|
||||||
|
string image = 4;
|
||||||
|
repeated int32 ports = 5;
|
||||||
|
string status = 6;
|
||||||
|
google.protobuf.Timestamp created = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetContainerRequest {
|
||||||
|
string id = 1;
|
||||||
|
string hostname = 2;
|
||||||
|
string public_ip = 3;
|
||||||
|
repeated string private_ips = 4;
|
||||||
|
repeated Container containers = 5;
|
||||||
|
google.protobuf.Timestamp last_seen = 6;
|
||||||
|
}
|
||||||
|
message GetContainerResponse {}
|
||||||
|
|
||||||
|
message RefreshTokenRequest {
|
||||||
|
string token = 1;
|
||||||
|
}
|
||||||
|
message RefreshTokenResponse {
|
||||||
|
string token = 1;
|
||||||
|
}
|
||||||
13
agent/proto/buf.gen.yaml
Normal file
13
agent/proto/buf.gen.yaml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
version: v2
|
||||||
|
managed:
|
||||||
|
enabled: true
|
||||||
|
override:
|
||||||
|
- file_option: go_package_prefix
|
||||||
|
value: github.com/MizuchiLabs/mantrae/agent/proto/gen
|
||||||
|
plugins:
|
||||||
|
- local: protoc-gen-go
|
||||||
|
out: gen
|
||||||
|
opt: paths=source_relative
|
||||||
|
- local: protoc-gen-connect-go
|
||||||
|
out: gen
|
||||||
|
opt: paths=source_relative
|
||||||
8
agent/proto/buf.yaml
Normal file
8
agent/proto/buf.yaml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# For details on buf.yaml configuration, visit https://buf.build/docs/configuration/v2/buf-yaml
|
||||||
|
version: v2
|
||||||
|
lint:
|
||||||
|
use:
|
||||||
|
- STANDARD
|
||||||
|
breaking:
|
||||||
|
use:
|
||||||
|
- FILE
|
||||||
532
agent/proto/gen/agent/v1/agent.pb.go
Normal file
532
agent/proto/gen/agent/v1/agent.pb.go
Normal file
@@ -0,0 +1,532 @@
|
|||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// protoc-gen-go v1.34.2
|
||||||
|
// protoc (unknown)
|
||||||
|
// source: agent/v1/agent.proto
|
||||||
|
|
||||||
|
package agentv1
|
||||||
|
|
||||||
|
import (
|
||||||
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
|
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
|
||||||
|
reflect "reflect"
|
||||||
|
sync "sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Verify that this generated code is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||||
|
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
|
)
|
||||||
|
|
||||||
|
type Container struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||||
|
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
|
||||||
|
Labels map[string]string `protobuf:"bytes,3,rep,name=labels,proto3" json:"labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||||
|
Image string `protobuf:"bytes,4,opt,name=image,proto3" json:"image,omitempty"`
|
||||||
|
Ports []int32 `protobuf:"varint,5,rep,packed,name=ports,proto3" json:"ports,omitempty"`
|
||||||
|
Status string `protobuf:"bytes,6,opt,name=status,proto3" json:"status,omitempty"`
|
||||||
|
Created *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=created,proto3" json:"created,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Container) Reset() {
|
||||||
|
*x = Container{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_agent_v1_agent_proto_msgTypes[0]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Container) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*Container) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *Container) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_agent_v1_agent_proto_msgTypes[0]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use Container.ProtoReflect.Descriptor instead.
|
||||||
|
func (*Container) Descriptor() ([]byte, []int) {
|
||||||
|
return file_agent_v1_agent_proto_rawDescGZIP(), []int{0}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Container) GetId() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Id
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Container) GetName() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Name
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Container) GetLabels() map[string]string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Labels
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Container) GetImage() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Image
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Container) GetPorts() []int32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.Ports
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Container) GetStatus() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Status
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Container) GetCreated() *timestamppb.Timestamp {
|
||||||
|
if x != nil {
|
||||||
|
return x.Created
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetContainerRequest struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||||
|
Hostname string `protobuf:"bytes,2,opt,name=hostname,proto3" json:"hostname,omitempty"`
|
||||||
|
PublicIp string `protobuf:"bytes,3,opt,name=public_ip,json=publicIp,proto3" json:"public_ip,omitempty"`
|
||||||
|
PrivateIps []string `protobuf:"bytes,4,rep,name=private_ips,json=privateIps,proto3" json:"private_ips,omitempty"`
|
||||||
|
Containers []*Container `protobuf:"bytes,5,rep,name=containers,proto3" json:"containers,omitempty"`
|
||||||
|
LastSeen *timestamppb.Timestamp `protobuf:"bytes,6,opt,name=last_seen,json=lastSeen,proto3" json:"last_seen,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetContainerRequest) Reset() {
|
||||||
|
*x = GetContainerRequest{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_agent_v1_agent_proto_msgTypes[1]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetContainerRequest) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*GetContainerRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *GetContainerRequest) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_agent_v1_agent_proto_msgTypes[1]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use GetContainerRequest.ProtoReflect.Descriptor instead.
|
||||||
|
func (*GetContainerRequest) Descriptor() ([]byte, []int) {
|
||||||
|
return file_agent_v1_agent_proto_rawDescGZIP(), []int{1}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetContainerRequest) GetId() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Id
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetContainerRequest) GetHostname() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Hostname
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetContainerRequest) GetPublicIp() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.PublicIp
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetContainerRequest) GetPrivateIps() []string {
|
||||||
|
if x != nil {
|
||||||
|
return x.PrivateIps
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetContainerRequest) GetContainers() []*Container {
|
||||||
|
if x != nil {
|
||||||
|
return x.Containers
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetContainerRequest) GetLastSeen() *timestamppb.Timestamp {
|
||||||
|
if x != nil {
|
||||||
|
return x.LastSeen
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetContainerResponse struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetContainerResponse) Reset() {
|
||||||
|
*x = GetContainerResponse{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_agent_v1_agent_proto_msgTypes[2]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetContainerResponse) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*GetContainerResponse) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *GetContainerResponse) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_agent_v1_agent_proto_msgTypes[2]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use GetContainerResponse.ProtoReflect.Descriptor instead.
|
||||||
|
func (*GetContainerResponse) Descriptor() ([]byte, []int) {
|
||||||
|
return file_agent_v1_agent_proto_rawDescGZIP(), []int{2}
|
||||||
|
}
|
||||||
|
|
||||||
|
type RefreshTokenRequest struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *RefreshTokenRequest) Reset() {
|
||||||
|
*x = RefreshTokenRequest{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_agent_v1_agent_proto_msgTypes[3]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *RefreshTokenRequest) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*RefreshTokenRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *RefreshTokenRequest) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_agent_v1_agent_proto_msgTypes[3]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use RefreshTokenRequest.ProtoReflect.Descriptor instead.
|
||||||
|
func (*RefreshTokenRequest) Descriptor() ([]byte, []int) {
|
||||||
|
return file_agent_v1_agent_proto_rawDescGZIP(), []int{3}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *RefreshTokenRequest) GetToken() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Token
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type RefreshTokenResponse struct {
|
||||||
|
state protoimpl.MessageState
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
|
||||||
|
Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *RefreshTokenResponse) Reset() {
|
||||||
|
*x = RefreshTokenResponse{}
|
||||||
|
if protoimpl.UnsafeEnabled {
|
||||||
|
mi := &file_agent_v1_agent_proto_msgTypes[4]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *RefreshTokenResponse) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*RefreshTokenResponse) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *RefreshTokenResponse) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_agent_v1_agent_proto_msgTypes[4]
|
||||||
|
if protoimpl.UnsafeEnabled && x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use RefreshTokenResponse.ProtoReflect.Descriptor instead.
|
||||||
|
func (*RefreshTokenResponse) Descriptor() ([]byte, []int) {
|
||||||
|
return file_agent_v1_agent_proto_rawDescGZIP(), []int{4}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *RefreshTokenResponse) GetToken() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Token
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
var File_agent_v1_agent_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
|
var file_agent_v1_agent_proto_rawDesc = []byte{
|
||||||
|
0x0a, 0x14, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74,
|
||||||
|
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31,
|
||||||
|
0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
|
||||||
|
0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||||
|
0x6f, 0x22, 0x9d, 0x02, 0x0a, 0x09, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x12,
|
||||||
|
0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12,
|
||||||
|
0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e,
|
||||||
|
0x61, 0x6d, 0x65, 0x12, 0x37, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x03, 0x20,
|
||||||
|
0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x43,
|
||||||
|
0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45,
|
||||||
|
0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x14, 0x0a, 0x05,
|
||||||
|
0x69, 0x6d, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x69, 0x6d, 0x61,
|
||||||
|
0x67, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28,
|
||||||
|
0x05, 0x52, 0x05, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74,
|
||||||
|
0x75, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73,
|
||||||
|
0x12, 0x34, 0x0a, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28,
|
||||||
|
0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||||
|
0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x63,
|
||||||
|
0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x1a, 0x39, 0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73,
|
||||||
|
0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
|
||||||
|
0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
|
||||||
|
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
|
||||||
|
0x01, 0x22, 0xed, 0x01, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e,
|
||||||
|
0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18,
|
||||||
|
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x68, 0x6f, 0x73,
|
||||||
|
0x74, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x6f, 0x73,
|
||||||
|
0x74, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f,
|
||||||
|
0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63,
|
||||||
|
0x49, 0x70, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x70,
|
||||||
|
0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65,
|
||||||
|
0x49, 0x70, 0x73, 0x12, 0x33, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72,
|
||||||
|
0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e,
|
||||||
|
0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x0a, 0x63, 0x6f,
|
||||||
|
0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x12, 0x37, 0x0a, 0x09, 0x6c, 0x61, 0x73, 0x74,
|
||||||
|
0x5f, 0x73, 0x65, 0x65, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f,
|
||||||
|
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69,
|
||||||
|
0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x08, 0x6c, 0x61, 0x73, 0x74, 0x53, 0x65, 0x65,
|
||||||
|
0x6e, 0x22, 0x16, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65,
|
||||||
|
0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2b, 0x0a, 0x13, 0x52, 0x65, 0x66,
|
||||||
|
0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||||
|
0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||||
|
0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x2c, 0x0a, 0x14, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73,
|
||||||
|
0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14,
|
||||||
|
0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74,
|
||||||
|
0x6f, 0x6b, 0x65, 0x6e, 0x32, 0xac, 0x01, 0x0a, 0x0c, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x53, 0x65,
|
||||||
|
0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x4d, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x74,
|
||||||
|
0x61, 0x69, 0x6e, 0x65, 0x72, 0x12, 0x1d, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31,
|
||||||
|
0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x71,
|
||||||
|
0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e,
|
||||||
|
0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70,
|
||||||
|
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x0c, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54,
|
||||||
|
0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1d, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e,
|
||||||
|
0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75,
|
||||||
|
0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x76, 0x31, 0x2e, 0x52,
|
||||||
|
0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||||
|
0x6e, 0x73, 0x65, 0x42, 0x9c, 0x01, 0x0a, 0x0c, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x67, 0x65, 0x6e,
|
||||||
|
0x74, 0x2e, 0x76, 0x31, 0x42, 0x0a, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x50, 0x72, 0x6f, 0x74, 0x6f,
|
||||||
|
0x50, 0x01, 0x5a, 0x3f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x4d,
|
||||||
|
0x69, 0x7a, 0x75, 0x63, 0x68, 0x69, 0x4c, 0x61, 0x62, 0x73, 0x2f, 0x6d, 0x61, 0x6e, 0x74, 0x72,
|
||||||
|
0x61, 0x65, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67,
|
||||||
|
0x65, 0x6e, 0x2f, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x2f, 0x76, 0x31, 0x3b, 0x61, 0x67, 0x65, 0x6e,
|
||||||
|
0x74, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x41, 0x58, 0x58, 0xaa, 0x02, 0x08, 0x41, 0x67, 0x65, 0x6e,
|
||||||
|
0x74, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x08, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x5c, 0x56, 0x31, 0xe2,
|
||||||
|
0x02, 0x14, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65,
|
||||||
|
0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x09, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x3a, 0x3a,
|
||||||
|
0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
file_agent_v1_agent_proto_rawDescOnce sync.Once
|
||||||
|
file_agent_v1_agent_proto_rawDescData = file_agent_v1_agent_proto_rawDesc
|
||||||
|
)
|
||||||
|
|
||||||
|
func file_agent_v1_agent_proto_rawDescGZIP() []byte {
|
||||||
|
file_agent_v1_agent_proto_rawDescOnce.Do(func() {
|
||||||
|
file_agent_v1_agent_proto_rawDescData = protoimpl.X.CompressGZIP(file_agent_v1_agent_proto_rawDescData)
|
||||||
|
})
|
||||||
|
return file_agent_v1_agent_proto_rawDescData
|
||||||
|
}
|
||||||
|
|
||||||
|
var file_agent_v1_agent_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
|
||||||
|
var file_agent_v1_agent_proto_goTypes = []any{
|
||||||
|
(*Container)(nil), // 0: agent.v1.Container
|
||||||
|
(*GetContainerRequest)(nil), // 1: agent.v1.GetContainerRequest
|
||||||
|
(*GetContainerResponse)(nil), // 2: agent.v1.GetContainerResponse
|
||||||
|
(*RefreshTokenRequest)(nil), // 3: agent.v1.RefreshTokenRequest
|
||||||
|
(*RefreshTokenResponse)(nil), // 4: agent.v1.RefreshTokenResponse
|
||||||
|
nil, // 5: agent.v1.Container.LabelsEntry
|
||||||
|
(*timestamppb.Timestamp)(nil), // 6: google.protobuf.Timestamp
|
||||||
|
}
|
||||||
|
var file_agent_v1_agent_proto_depIdxs = []int32{
|
||||||
|
5, // 0: agent.v1.Container.labels:type_name -> agent.v1.Container.LabelsEntry
|
||||||
|
6, // 1: agent.v1.Container.created:type_name -> google.protobuf.Timestamp
|
||||||
|
0, // 2: agent.v1.GetContainerRequest.containers:type_name -> agent.v1.Container
|
||||||
|
6, // 3: agent.v1.GetContainerRequest.last_seen:type_name -> google.protobuf.Timestamp
|
||||||
|
1, // 4: agent.v1.AgentService.GetContainer:input_type -> agent.v1.GetContainerRequest
|
||||||
|
3, // 5: agent.v1.AgentService.RefreshToken:input_type -> agent.v1.RefreshTokenRequest
|
||||||
|
2, // 6: agent.v1.AgentService.GetContainer:output_type -> agent.v1.GetContainerResponse
|
||||||
|
4, // 7: agent.v1.AgentService.RefreshToken:output_type -> agent.v1.RefreshTokenResponse
|
||||||
|
6, // [6:8] is the sub-list for method output_type
|
||||||
|
4, // [4:6] is the sub-list for method input_type
|
||||||
|
4, // [4:4] is the sub-list for extension type_name
|
||||||
|
4, // [4:4] is the sub-list for extension extendee
|
||||||
|
0, // [0:4] is the sub-list for field type_name
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { file_agent_v1_agent_proto_init() }
|
||||||
|
func file_agent_v1_agent_proto_init() {
|
||||||
|
if File_agent_v1_agent_proto != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !protoimpl.UnsafeEnabled {
|
||||||
|
file_agent_v1_agent_proto_msgTypes[0].Exporter = func(v any, i int) any {
|
||||||
|
switch v := v.(*Container); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_agent_v1_agent_proto_msgTypes[1].Exporter = func(v any, i int) any {
|
||||||
|
switch v := v.(*GetContainerRequest); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_agent_v1_agent_proto_msgTypes[2].Exporter = func(v any, i int) any {
|
||||||
|
switch v := v.(*GetContainerResponse); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_agent_v1_agent_proto_msgTypes[3].Exporter = func(v any, i int) any {
|
||||||
|
switch v := v.(*RefreshTokenRequest); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file_agent_v1_agent_proto_msgTypes[4].Exporter = func(v any, i int) any {
|
||||||
|
switch v := v.(*RefreshTokenResponse); i {
|
||||||
|
case 0:
|
||||||
|
return &v.state
|
||||||
|
case 1:
|
||||||
|
return &v.sizeCache
|
||||||
|
case 2:
|
||||||
|
return &v.unknownFields
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
type x struct{}
|
||||||
|
out := protoimpl.TypeBuilder{
|
||||||
|
File: protoimpl.DescBuilder{
|
||||||
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
|
RawDescriptor: file_agent_v1_agent_proto_rawDesc,
|
||||||
|
NumEnums: 0,
|
||||||
|
NumMessages: 6,
|
||||||
|
NumExtensions: 0,
|
||||||
|
NumServices: 1,
|
||||||
|
},
|
||||||
|
GoTypes: file_agent_v1_agent_proto_goTypes,
|
||||||
|
DependencyIndexes: file_agent_v1_agent_proto_depIdxs,
|
||||||
|
MessageInfos: file_agent_v1_agent_proto_msgTypes,
|
||||||
|
}.Build()
|
||||||
|
File_agent_v1_agent_proto = out.File
|
||||||
|
file_agent_v1_agent_proto_rawDesc = nil
|
||||||
|
file_agent_v1_agent_proto_goTypes = nil
|
||||||
|
file_agent_v1_agent_proto_depIdxs = nil
|
||||||
|
}
|
||||||
143
agent/proto/gen/agent/v1/agentv1connect/agent.connect.go
Normal file
143
agent/proto/gen/agent/v1/agentv1connect/agent.connect.go
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
// Code generated by protoc-gen-connect-go. DO NOT EDIT.
|
||||||
|
//
|
||||||
|
// Source: agent/v1/agent.proto
|
||||||
|
|
||||||
|
package agentv1connect
|
||||||
|
|
||||||
|
import (
|
||||||
|
connect "connectrpc.com/connect"
|
||||||
|
context "context"
|
||||||
|
errors "errors"
|
||||||
|
v1 "github.com/MizuchiLabs/mantrae/agent/proto/gen/agent/v1"
|
||||||
|
http "net/http"
|
||||||
|
strings "strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file and the connect package are
|
||||||
|
// compatible. If you get a compiler error that this constant is not defined, this code was
|
||||||
|
// generated with a version of connect newer than the one compiled into your binary. You can fix the
|
||||||
|
// problem by either regenerating this code with an older version of connect or updating the connect
|
||||||
|
// version compiled into your binary.
|
||||||
|
const _ = connect.IsAtLeastVersion1_13_0
|
||||||
|
|
||||||
|
const (
|
||||||
|
// AgentServiceName is the fully-qualified name of the AgentService service.
|
||||||
|
AgentServiceName = "agent.v1.AgentService"
|
||||||
|
)
|
||||||
|
|
||||||
|
// These constants are the fully-qualified names of the RPCs defined in this package. They're
|
||||||
|
// exposed at runtime as Spec.Procedure and as the final two segments of the HTTP route.
|
||||||
|
//
|
||||||
|
// Note that these are different from the fully-qualified method names used by
|
||||||
|
// google.golang.org/protobuf/reflect/protoreflect. To convert from these constants to
|
||||||
|
// reflection-formatted method names, remove the leading slash and convert the remaining slash to a
|
||||||
|
// period.
|
||||||
|
const (
|
||||||
|
// AgentServiceGetContainerProcedure is the fully-qualified name of the AgentService's GetContainer
|
||||||
|
// RPC.
|
||||||
|
AgentServiceGetContainerProcedure = "/agent.v1.AgentService/GetContainer"
|
||||||
|
// AgentServiceRefreshTokenProcedure is the fully-qualified name of the AgentService's RefreshToken
|
||||||
|
// RPC.
|
||||||
|
AgentServiceRefreshTokenProcedure = "/agent.v1.AgentService/RefreshToken"
|
||||||
|
)
|
||||||
|
|
||||||
|
// These variables are the protoreflect.Descriptor objects for the RPCs defined in this package.
|
||||||
|
var (
|
||||||
|
agentServiceServiceDescriptor = v1.File_agent_v1_agent_proto.Services().ByName("AgentService")
|
||||||
|
agentServiceGetContainerMethodDescriptor = agentServiceServiceDescriptor.Methods().ByName("GetContainer")
|
||||||
|
agentServiceRefreshTokenMethodDescriptor = agentServiceServiceDescriptor.Methods().ByName("RefreshToken")
|
||||||
|
)
|
||||||
|
|
||||||
|
// AgentServiceClient is a client for the agent.v1.AgentService service.
|
||||||
|
type AgentServiceClient interface {
|
||||||
|
GetContainer(context.Context, *connect.Request[v1.GetContainerRequest]) (*connect.Response[v1.GetContainerResponse], error)
|
||||||
|
RefreshToken(context.Context, *connect.Request[v1.RefreshTokenRequest]) (*connect.Response[v1.RefreshTokenResponse], error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAgentServiceClient constructs a client for the agent.v1.AgentService service. By default, it
|
||||||
|
// uses the Connect protocol with the binary Protobuf Codec, asks for gzipped responses, and sends
|
||||||
|
// uncompressed requests. To use the gRPC or gRPC-Web protocols, supply the connect.WithGRPC() or
|
||||||
|
// connect.WithGRPCWeb() options.
|
||||||
|
//
|
||||||
|
// The URL supplied here should be the base URL for the Connect or gRPC server (for example,
|
||||||
|
// http://api.acme.com or https://acme.com/grpc).
|
||||||
|
func NewAgentServiceClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) AgentServiceClient {
|
||||||
|
baseURL = strings.TrimRight(baseURL, "/")
|
||||||
|
return &agentServiceClient{
|
||||||
|
getContainer: connect.NewClient[v1.GetContainerRequest, v1.GetContainerResponse](
|
||||||
|
httpClient,
|
||||||
|
baseURL+AgentServiceGetContainerProcedure,
|
||||||
|
connect.WithSchema(agentServiceGetContainerMethodDescriptor),
|
||||||
|
connect.WithClientOptions(opts...),
|
||||||
|
),
|
||||||
|
refreshToken: connect.NewClient[v1.RefreshTokenRequest, v1.RefreshTokenResponse](
|
||||||
|
httpClient,
|
||||||
|
baseURL+AgentServiceRefreshTokenProcedure,
|
||||||
|
connect.WithSchema(agentServiceRefreshTokenMethodDescriptor),
|
||||||
|
connect.WithClientOptions(opts...),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// agentServiceClient implements AgentServiceClient.
|
||||||
|
type agentServiceClient struct {
|
||||||
|
getContainer *connect.Client[v1.GetContainerRequest, v1.GetContainerResponse]
|
||||||
|
refreshToken *connect.Client[v1.RefreshTokenRequest, v1.RefreshTokenResponse]
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetContainer calls agent.v1.AgentService.GetContainer.
|
||||||
|
func (c *agentServiceClient) GetContainer(ctx context.Context, req *connect.Request[v1.GetContainerRequest]) (*connect.Response[v1.GetContainerResponse], error) {
|
||||||
|
return c.getContainer.CallUnary(ctx, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RefreshToken calls agent.v1.AgentService.RefreshToken.
|
||||||
|
func (c *agentServiceClient) RefreshToken(ctx context.Context, req *connect.Request[v1.RefreshTokenRequest]) (*connect.Response[v1.RefreshTokenResponse], error) {
|
||||||
|
return c.refreshToken.CallUnary(ctx, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
// AgentServiceHandler is an implementation of the agent.v1.AgentService service.
|
||||||
|
type AgentServiceHandler interface {
|
||||||
|
GetContainer(context.Context, *connect.Request[v1.GetContainerRequest]) (*connect.Response[v1.GetContainerResponse], error)
|
||||||
|
RefreshToken(context.Context, *connect.Request[v1.RefreshTokenRequest]) (*connect.Response[v1.RefreshTokenResponse], error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAgentServiceHandler builds an HTTP handler from the service implementation. It returns the
|
||||||
|
// path on which to mount the handler and the handler itself.
|
||||||
|
//
|
||||||
|
// By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf
|
||||||
|
// and JSON codecs. They also support gzip compression.
|
||||||
|
func NewAgentServiceHandler(svc AgentServiceHandler, opts ...connect.HandlerOption) (string, http.Handler) {
|
||||||
|
agentServiceGetContainerHandler := connect.NewUnaryHandler(
|
||||||
|
AgentServiceGetContainerProcedure,
|
||||||
|
svc.GetContainer,
|
||||||
|
connect.WithSchema(agentServiceGetContainerMethodDescriptor),
|
||||||
|
connect.WithHandlerOptions(opts...),
|
||||||
|
)
|
||||||
|
agentServiceRefreshTokenHandler := connect.NewUnaryHandler(
|
||||||
|
AgentServiceRefreshTokenProcedure,
|
||||||
|
svc.RefreshToken,
|
||||||
|
connect.WithSchema(agentServiceRefreshTokenMethodDescriptor),
|
||||||
|
connect.WithHandlerOptions(opts...),
|
||||||
|
)
|
||||||
|
return "/agent.v1.AgentService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
switch r.URL.Path {
|
||||||
|
case AgentServiceGetContainerProcedure:
|
||||||
|
agentServiceGetContainerHandler.ServeHTTP(w, r)
|
||||||
|
case AgentServiceRefreshTokenProcedure:
|
||||||
|
agentServiceRefreshTokenHandler.ServeHTTP(w, r)
|
||||||
|
default:
|
||||||
|
http.NotFound(w, r)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnimplementedAgentServiceHandler returns CodeUnimplemented from all methods.
|
||||||
|
type UnimplementedAgentServiceHandler struct{}
|
||||||
|
|
||||||
|
func (UnimplementedAgentServiceHandler) GetContainer(context.Context, *connect.Request[v1.GetContainerRequest]) (*connect.Response[v1.GetContainerResponse], error) {
|
||||||
|
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("agent.v1.AgentService.GetContainer is not implemented"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (UnimplementedAgentServiceHandler) RefreshToken(context.Context, *connect.Request[v1.RefreshTokenRequest]) (*connect.Response[v1.RefreshTokenResponse], error) {
|
||||||
|
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("agent.v1.AgentService.RefreshToken is not implemented"))
|
||||||
|
}
|
||||||
26
go.mod
26
go.mod
@@ -7,6 +7,7 @@ require github.com/traefik/genconf v0.5.2
|
|||||||
require (
|
require (
|
||||||
connectrpc.com/connect v1.17.0
|
connectrpc.com/connect v1.17.0
|
||||||
github.com/cloudflare/cloudflare-go v0.106.0
|
github.com/cloudflare/cloudflare-go v0.106.0
|
||||||
|
github.com/docker/docker v27.3.1+incompatible
|
||||||
github.com/golang-jwt/jwt/v5 v5.2.1
|
github.com/golang-jwt/jwt/v5 v5.2.1
|
||||||
github.com/joeig/go-powerdns/v3 v3.14.1
|
github.com/joeig/go-powerdns/v3 v3.14.1
|
||||||
github.com/lmittmann/tint v1.0.5
|
github.com/lmittmann/tint v1.0.5
|
||||||
@@ -14,19 +15,42 @@ require (
|
|||||||
github.com/pressly/goose/v3 v3.22.1
|
github.com/pressly/goose/v3 v3.22.1
|
||||||
github.com/robfig/cron/v3 v3.0.1
|
github.com/robfig/cron/v3 v3.0.1
|
||||||
golang.org/x/crypto v0.27.0
|
golang.org/x/crypto v0.27.0
|
||||||
|
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8
|
||||||
golang.org/x/net v0.29.0
|
golang.org/x/net v0.29.0
|
||||||
google.golang.org/protobuf v1.34.2
|
google.golang.org/protobuf v1.34.2
|
||||||
sigs.k8s.io/yaml v1.4.0
|
sigs.k8s.io/yaml v1.4.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/Microsoft/go-winio v0.4.14 // indirect
|
||||||
|
github.com/containerd/log v0.1.0 // indirect
|
||||||
|
github.com/distribution/reference v0.6.0 // indirect
|
||||||
|
github.com/docker/go-connections v0.5.0 // indirect
|
||||||
|
github.com/docker/go-units v0.5.0 // indirect
|
||||||
|
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||||
|
github.com/go-logr/logr v1.4.2 // indirect
|
||||||
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
github.com/goccy/go-json v0.10.3 // indirect
|
github.com/goccy/go-json v0.10.3 // indirect
|
||||||
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
github.com/google/go-querystring v1.1.0 // indirect
|
github.com/google/go-querystring v1.1.0 // indirect
|
||||||
github.com/kr/text v0.2.0 // indirect
|
|
||||||
github.com/mfridman/interpolate v0.0.2 // indirect
|
github.com/mfridman/interpolate v0.0.2 // indirect
|
||||||
|
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||||
|
github.com/moby/term v0.5.0 // indirect
|
||||||
|
github.com/morikuni/aec v1.0.0 // indirect
|
||||||
|
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||||
|
github.com/opencontainers/image-spec v1.1.0 // indirect
|
||||||
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/sethvargo/go-retry v0.3.0 // indirect
|
github.com/sethvargo/go-retry v0.3.0 // indirect
|
||||||
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0 // indirect
|
||||||
|
go.opentelemetry.io/otel v1.30.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.30.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/metric v1.30.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/sdk v1.30.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/trace v1.30.0 // indirect
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
golang.org/x/sync v0.8.0 // indirect
|
golang.org/x/sync v0.8.0 // indirect
|
||||||
|
golang.org/x/sys v0.25.0 // indirect
|
||||||
golang.org/x/text v0.18.0 // indirect
|
golang.org/x/text v0.18.0 // indirect
|
||||||
golang.org/x/time v0.6.0 // indirect
|
golang.org/x/time v0.6.0 // indirect
|
||||||
|
gotest.tools/v3 v3.5.1 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
106
go.sum
106
go.sum
@@ -1,29 +1,59 @@
|
|||||||
connectrpc.com/connect v1.17.0 h1:W0ZqMhtVzn9Zhn2yATuUokDLO5N+gIuBWMOnsQrfmZk=
|
connectrpc.com/connect v1.17.0 h1:W0ZqMhtVzn9Zhn2yATuUokDLO5N+gIuBWMOnsQrfmZk=
|
||||||
connectrpc.com/connect v1.17.0/go.mod h1:0292hj1rnx8oFrStN7cB4jjVBeqs+Yx5yDIC2prWDO8=
|
connectrpc.com/connect v1.17.0/go.mod h1:0292hj1rnx8oFrStN7cB4jjVBeqs+Yx5yDIC2prWDO8=
|
||||||
|
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
|
||||||
|
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||||
|
github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU=
|
||||||
|
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
|
||||||
|
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||||
|
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||||
github.com/cloudflare/cloudflare-go v0.106.0 h1:q41gC5Wc1nfi0D1ZhSHokWcd9mGMbqC7RE7qiP+qE00=
|
github.com/cloudflare/cloudflare-go v0.106.0 h1:q41gC5Wc1nfi0D1ZhSHokWcd9mGMbqC7RE7qiP+qE00=
|
||||||
github.com/cloudflare/cloudflare-go v0.106.0/go.mod h1:pfUQ4PIG4ISI0/Mmc21Bp86UnFU0ktmPf3iTgbSL+cM=
|
github.com/cloudflare/cloudflare-go v0.106.0/go.mod h1:pfUQ4PIG4ISI0/Mmc21Bp86UnFU0ktmPf3iTgbSL+cM=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||||
|
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
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/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
||||||
|
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||||
|
github.com/docker/docker v27.3.1+incompatible h1:KttF0XoteNTicmUtBO0L2tP+J7FGRFTjaEF4k6WdhfI=
|
||||||
|
github.com/docker/docker v27.3.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||||
|
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
||||||
|
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
||||||
|
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||||
|
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||||
|
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||||
|
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||||
|
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
|
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||||
|
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
|
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||||
|
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
|
github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
|
||||||
github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||||
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
|
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
|
||||||
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
|
||||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
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/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||||
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
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/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I=
|
||||||
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
||||||
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||||
github.com/jarcoal/httpmock v1.3.1 h1:iUx3whfZWVf3jT01hQTO/Eo5sAYtB2/rqaUuOtpInww=
|
github.com/jarcoal/httpmock v1.3.1 h1:iUx3whfZWVf3jT01hQTO/Eo5sAYtB2/rqaUuOtpInww=
|
||||||
github.com/jarcoal/httpmock v1.3.1/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg=
|
github.com/jarcoal/httpmock v1.3.1/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg=
|
||||||
github.com/joeig/go-powerdns/v3 v3.14.1 h1:ff+ClS/yM5ZBigh5oe4m0T/Na2k0k+JNpyuby0LkGCc=
|
github.com/joeig/go-powerdns/v3 v3.14.1 h1:ff+ClS/yM5ZBigh5oe4m0T/Na2k0k+JNpyuby0LkGCc=
|
||||||
github.com/joeig/go-powerdns/v3 v3.14.1/go.mod h1:hA54LX2p4A/Jp1Kgdhd7Lh3jAU0u7wV1mk1JbGywt60=
|
github.com/joeig/go-powerdns/v3 v3.14.1/go.mod h1:hA54LX2p4A/Jp1Kgdhd7Lh3jAU0u7wV1mk1JbGywt60=
|
||||||
|
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
@@ -36,8 +66,21 @@ github.com/mattn/go-sqlite3 v1.14.23 h1:gbShiuAP1W5j9UOksQ06aiiqPMxYecovVGwmTxWt
|
|||||||
github.com/mattn/go-sqlite3 v1.14.23/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
github.com/mattn/go-sqlite3 v1.14.23/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||||
github.com/mfridman/interpolate v0.0.2 h1:pnuTK7MQIxxFz1Gr+rjSIx9u7qVjf5VOoM/u6BbAxPY=
|
github.com/mfridman/interpolate v0.0.2 h1:pnuTK7MQIxxFz1Gr+rjSIx9u7qVjf5VOoM/u6BbAxPY=
|
||||||
github.com/mfridman/interpolate v0.0.2/go.mod h1:p+7uk6oE07mpE/Ik1b8EckO0O4ZXiGAfshKBWLUM9Xg=
|
github.com/mfridman/interpolate v0.0.2/go.mod h1:p+7uk6oE07mpE/Ik1b8EckO0O4ZXiGAfshKBWLUM9Xg=
|
||||||
|
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
|
||||||
|
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
|
||||||
|
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
|
||||||
|
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
|
||||||
|
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||||
|
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||||
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
||||||
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||||
|
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||||
|
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||||
|
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
|
||||||
|
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
|
||||||
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/pressly/goose/v3 v3.22.1 h1:2zICEfr1O3yTP9BRZMGPj7qFxQ+ik6yeo+z1LMuioLc=
|
github.com/pressly/goose/v3 v3.22.1 h1:2zICEfr1O3yTP9BRZMGPj7qFxQ+ik6yeo+z1LMuioLc=
|
||||||
@@ -50,25 +93,82 @@ github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XF
|
|||||||
github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
|
github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
|
||||||
github.com/sethvargo/go-retry v0.3.0 h1:EEt31A35QhrcRZtrYFDTBg91cqZVnFL2navjDrah2SE=
|
github.com/sethvargo/go-retry v0.3.0 h1:EEt31A35QhrcRZtrYFDTBg91cqZVnFL2navjDrah2SE=
|
||||||
github.com/sethvargo/go-retry v0.3.0/go.mod h1:mNX17F0C/HguQMyMyJxcnU471gOZGxCLyYaFyAZraas=
|
github.com/sethvargo/go-retry v0.3.0/go.mod h1:mNX17F0C/HguQMyMyJxcnU471gOZGxCLyYaFyAZraas=
|
||||||
|
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||||
|
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||||
|
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
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/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/traefik/genconf v0.5.2 h1:R90hthLOCU15OwVa1p5gbqkKdpXj77iIk7Ysk2r6beg=
|
github.com/traefik/genconf v0.5.2 h1:R90hthLOCU15OwVa1p5gbqkKdpXj77iIk7Ysk2r6beg=
|
||||||
github.com/traefik/genconf v0.5.2/go.mod h1:D3wUYg0jGF3ScEMOaNOXlqobGDiIbpr4QEwWK3HCQlg=
|
github.com/traefik/genconf v0.5.2/go.mod h1:D3wUYg0jGF3ScEMOaNOXlqobGDiIbpr4QEwWK3HCQlg=
|
||||||
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0 h1:ZIg3ZT/aQ7AfKqdwp7ECpOK6vHqquXXuyTjIO8ZdmPs=
|
||||||
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0/go.mod h1:DQAwmETtZV00skUwgD6+0U89g80NKsJE3DCKeLLPQMI=
|
||||||
|
go.opentelemetry.io/otel v1.30.0 h1:F2t8sK4qf1fAmY9ua4ohFS/K+FUuOPemHUIXHtktrts=
|
||||||
|
go.opentelemetry.io/otel v1.30.0/go.mod h1:tFw4Br9b7fOS+uEao81PJjVMjW/5fvNCbpsDIXqP0pc=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0 h1:lsInsfvhVIfOI6qHVyysXMNDnjO9Npvl7tlDPJFBVd4=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.30.0/go.mod h1:KQsVNh4OjgjTG0G6EiNi1jVpnaeeKsKMRwbLN+f1+8M=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.30.0 h1:umZgi92IyxfXd/l4kaDhnKgY8rnN/cZcF1LKc6I8OQ8=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.30.0/go.mod h1:4lVs6obhSVRb1EW5FhOuBTyiQhtRtAnnva9vD3yRfq8=
|
||||||
|
go.opentelemetry.io/otel/metric v1.30.0 h1:4xNulvn9gjzo4hjg+wzIKG7iNFEaBMX00Qd4QIZs7+w=
|
||||||
|
go.opentelemetry.io/otel/metric v1.30.0/go.mod h1:aXTfST94tswhWEb+5QjlSqG+cZlmyXy/u8jFpor3WqQ=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.30.0 h1:cHdik6irO49R5IysVhdn8oaiR9m8XluDaJAs4DfOrYE=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.30.0/go.mod h1:p14X4Ok8S+sygzblytT1nqG98QG2KYKv++HE0LY/mhg=
|
||||||
|
go.opentelemetry.io/otel/trace v1.30.0 h1:7UBkkYzeg3C7kQX8VAidWh2biiQbtAKjyIML8dQ9wmc=
|
||||||
|
go.opentelemetry.io/otel/trace v1.30.0/go.mod h1:5EyKqTzzmyqB9bwtCCq6pDLktPK6fmGf/Dph+8VI02o=
|
||||||
|
go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
|
||||||
|
go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
|
||||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
|
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
|
||||||
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
|
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
|
||||||
|
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 h1:aAcj0Da7eBAtrTp03QXWvm88pSyOt+UgdZw2BFZ+lEw=
|
||||||
|
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ=
|
||||||
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
|
golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
|
||||||
golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
|
golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||||
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
|
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
|
||||||
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
|
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
|
||||||
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||||
golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
|
golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
|
||||||
golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
|
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 h1:hjSy6tcFQZ171igDaN5QHOw2n6vx40juYbC/x67CEhc=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
|
||||||
|
google.golang.org/grpc v1.66.1 h1:hO5qAXR19+/Z44hmvIM4dQFMSYX9XcWsByfoxutBpAM=
|
||||||
|
google.golang.org/grpc v1.66.1/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
|
||||||
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
||||||
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
@@ -76,6 +176,8 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN
|
|||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
|
||||||
|
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
|
||||||
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQXS2NxAhyWQvkKEgXZhHI=
|
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQXS2NxAhyWQvkKEgXZhHI=
|
||||||
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4=
|
modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4=
|
||||||
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
|
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
|
||||||
|
|||||||
@@ -2,22 +2,48 @@ package api
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"log/slog"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"connectrpc.com/connect"
|
"connectrpc.com/connect"
|
||||||
"golang.org/x/net/http2"
|
|
||||||
"golang.org/x/net/http2/h2c"
|
|
||||||
|
|
||||||
agentv1 "github.com/MizuchiLabs/mantrae/agent/proto/gen/agent/v1"
|
agentv1 "github.com/MizuchiLabs/mantrae/agent/proto/gen/agent/v1"
|
||||||
"github.com/MizuchiLabs/mantrae/agent/proto/gen/agent/v1/agentv1connect"
|
"github.com/MizuchiLabs/mantrae/agent/proto/gen/agent/v1/agentv1connect"
|
||||||
|
"github.com/MizuchiLabs/mantrae/internal/db"
|
||||||
|
"github.com/MizuchiLabs/mantrae/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AgentServer struct {
|
type AgentServer struct {
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
agents map[string]agentv1.GetContainerRequest
|
}
|
||||||
|
|
||||||
|
func (s *AgentServer) RefreshToken(
|
||||||
|
ctx context.Context,
|
||||||
|
req *connect.Request[agentv1.RefreshTokenRequest],
|
||||||
|
) (*connect.Response[agentv1.RefreshTokenResponse], error) {
|
||||||
|
if err := validate(req.Header()); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
decoded, err := util.DecodeJWT(req.Msg.GetToken())
|
||||||
|
if err != nil {
|
||||||
|
return nil, connect.NewError(connect.CodeInternal, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
token, err := util.EncodeAgentJWT(decoded.ServerURL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, connect.NewError(connect.CodeInternal, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return connect.NewResponse(&agentv1.RefreshTokenResponse{
|
||||||
|
Token: token,
|
||||||
|
}), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *AgentServer) GetContainer(
|
func (s *AgentServer) GetContainer(
|
||||||
@@ -28,22 +54,33 @@ func (s *AgentServer) GetContainer(
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add agent
|
// Upsert agent
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
s.agents[req.Msg.GetId()] = agentv1.GetContainerRequest{
|
privateIpsJSON, err := json.Marshal(req.Msg.GetPrivateIps())
|
||||||
Id: req.Msg.GetId(),
|
if err != nil {
|
||||||
|
s.mu.Unlock()
|
||||||
|
return nil, connect.NewError(connect.CodeInternal, err)
|
||||||
|
}
|
||||||
|
containersJSON, err := json.Marshal(req.Msg.GetContainers())
|
||||||
|
if err != nil {
|
||||||
|
s.mu.Unlock()
|
||||||
|
return nil, connect.NewError(connect.CodeInternal, err)
|
||||||
|
}
|
||||||
|
lastSeen := req.Msg.GetLastSeen().AsTime()
|
||||||
|
if _, err := db.Query.UpsertAgent(context.Background(), db.UpsertAgentParams{
|
||||||
|
ID: req.Msg.GetId(),
|
||||||
Hostname: req.Msg.GetHostname(),
|
Hostname: req.Msg.GetHostname(),
|
||||||
Containers: req.Msg.GetContainers(),
|
PublicIp: &req.Msg.PublicIp,
|
||||||
LastSeen: req.Msg.GetLastSeen(),
|
PrivateIps: privateIpsJSON,
|
||||||
|
Containers: containersJSON,
|
||||||
|
LastSeen: &lastSeen,
|
||||||
|
}); err != nil {
|
||||||
|
s.mu.Unlock()
|
||||||
|
return nil, connect.NewError(connect.CodeInternal, err)
|
||||||
}
|
}
|
||||||
s.mu.Unlock()
|
s.mu.Unlock()
|
||||||
return connect.NewResponse(&agentv1.GetContainerResponse{}), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *AgentServer) deleteAgent(id string) {
|
return connect.NewResponse(&agentv1.GetContainerResponse{}), nil
|
||||||
s.mu.Lock()
|
|
||||||
defer s.mu.Unlock()
|
|
||||||
delete(s.agents, id)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func validate(header http.Header) error {
|
func validate(header http.Header) error {
|
||||||
@@ -54,10 +91,7 @@ func validate(header http.Header) error {
|
|||||||
if !strings.HasPrefix(auth, "Bearer ") {
|
if !strings.HasPrefix(auth, "Bearer ") {
|
||||||
return connect.NewError(connect.CodeUnauthenticated, errors.New("missing bearer prefix"))
|
return connect.NewError(connect.CodeUnauthenticated, errors.New("missing bearer prefix"))
|
||||||
}
|
}
|
||||||
|
if strings.TrimSpace(os.Getenv("SECRET")) != strings.TrimPrefix(auth, "Bearer ") {
|
||||||
token := "test"
|
|
||||||
|
|
||||||
if strings.TrimSpace(string(token)) != strings.TrimPrefix(auth, "Bearer ") {
|
|
||||||
return connect.NewError(
|
return connect.NewError(
|
||||||
connect.CodeUnauthenticated,
|
connect.CodeUnauthenticated,
|
||||||
errors.New("failed to validate token"),
|
errors.New("failed to validate token"),
|
||||||
@@ -67,15 +101,35 @@ func validate(header http.Header) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func Server() {
|
func Server(port string) {
|
||||||
agent := &AgentServer{}
|
agent := &AgentServer{}
|
||||||
|
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
path, handler := agentv1connect.NewAgentServiceHandler(agent)
|
path, handler := agentv1connect.NewAgentServiceHandler(agent)
|
||||||
mux.Handle(path, handler)
|
mux.Handle(path, handler)
|
||||||
|
|
||||||
http.ListenAndServe(
|
if port == "" {
|
||||||
":8080",
|
port = ":8090"
|
||||||
h2c.NewHandler(mux, &http2.Server{}),
|
} else if !strings.HasPrefix(port, ":") {
|
||||||
)
|
port = ":" + port
|
||||||
|
}
|
||||||
|
srv := &http.Server{
|
||||||
|
Addr: port,
|
||||||
|
Handler: mux,
|
||||||
|
ReadHeaderTimeout: 10 * time.Second,
|
||||||
|
IdleTimeout: 120 * time.Second,
|
||||||
|
MaxHeaderBytes: 1 << 20, // 1MB
|
||||||
|
}
|
||||||
|
|
||||||
|
slog.Info("gRPC server running on", "port", port)
|
||||||
|
go func() {
|
||||||
|
if err := srv.ListenAndServe(); err != nil {
|
||||||
|
if err == http.ErrServerClosed {
|
||||||
|
slog.Info("gRPC server closed")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
slog.Error("gRPC server error", "err", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,57 +0,0 @@
|
|||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/golang-jwt/jwt/v5"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Claims struct {
|
|
||||||
Username string `json:"username"`
|
|
||||||
jwt.RegisteredClaims
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenerateJWT generates a JWT token
|
|
||||||
func GenerateJWT(username string) (string, error) {
|
|
||||||
expirationTime := time.Now().Add(24 * time.Hour)
|
|
||||||
claims := &Claims{
|
|
||||||
Username: username,
|
|
||||||
RegisteredClaims: jwt.RegisteredClaims{
|
|
||||||
ExpiresAt: jwt.NewNumericDate(expirationTime),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
if username == "" {
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
secret := os.Getenv("SECRET")
|
|
||||||
if secret == "" {
|
|
||||||
return "", fmt.Errorf("SECRET environment variable is not set")
|
|
||||||
}
|
|
||||||
|
|
||||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
|
||||||
return token.SignedString([]byte(secret))
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidateJWT validates a JWT token
|
|
||||||
func ValidateJWT(tokenString string) (*Claims, error) {
|
|
||||||
claims := &Claims{}
|
|
||||||
|
|
||||||
token, err := jwt.ParseWithClaims(
|
|
||||||
tokenString,
|
|
||||||
claims,
|
|
||||||
func(token *jwt.Token) (interface{}, error) {
|
|
||||||
return []byte(os.Getenv("SECRET")), nil
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if !token.Valid {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return claims, nil
|
|
||||||
}
|
|
||||||
@@ -1,156 +0,0 @@
|
|||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/golang-jwt/jwt/v5"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestGenerateJWT(t *testing.T) {
|
|
||||||
type args struct {
|
|
||||||
username string
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
args args
|
|
||||||
emptyToken bool
|
|
||||||
wantErr bool
|
|
||||||
setEnv bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "Valid Username",
|
|
||||||
args: args{
|
|
||||||
username: "testuser",
|
|
||||||
},
|
|
||||||
emptyToken: false,
|
|
||||||
wantErr: false,
|
|
||||||
setEnv: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Empty Username",
|
|
||||||
args: args{
|
|
||||||
username: "",
|
|
||||||
},
|
|
||||||
emptyToken: true,
|
|
||||||
wantErr: false,
|
|
||||||
setEnv: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Without Secret",
|
|
||||||
args: args{
|
|
||||||
username: "testuser",
|
|
||||||
},
|
|
||||||
emptyToken: false,
|
|
||||||
wantErr: true,
|
|
||||||
setEnv: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
if tt.setEnv {
|
|
||||||
os.Setenv("SECRET", "dummy-secret") // Set the secret environment variable
|
|
||||||
} else {
|
|
||||||
os.Unsetenv("SECRET")
|
|
||||||
}
|
|
||||||
token, err := GenerateJWT(tt.args.username)
|
|
||||||
if (err != nil) != tt.wantErr {
|
|
||||||
t.Errorf("GenerateJWT() error = %v, wantErr %v", err, tt.wantErr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if tt.emptyToken {
|
|
||||||
if token != "" {
|
|
||||||
t.Errorf("GenerateJWT() = %v, want empty string", token)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestValidateJWT(t *testing.T) {
|
|
||||||
os.Setenv("SECRET", "dummy-secret") // Set the secret environment variable
|
|
||||||
|
|
||||||
validToken, _ := GenerateJWT("testuser")
|
|
||||||
|
|
||||||
type args struct {
|
|
||||||
tokenString string
|
|
||||||
}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
args args
|
|
||||||
want *Claims
|
|
||||||
wantErr bool
|
|
||||||
setEnv bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "Valid Token",
|
|
||||||
args: args{
|
|
||||||
tokenString: validToken,
|
|
||||||
},
|
|
||||||
want: &Claims{
|
|
||||||
Username: "testuser",
|
|
||||||
RegisteredClaims: jwt.RegisteredClaims{
|
|
||||||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
wantErr: false,
|
|
||||||
setEnv: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Invalid Token",
|
|
||||||
args: args{
|
|
||||||
tokenString: "invalidTokenString",
|
|
||||||
},
|
|
||||||
want: nil,
|
|
||||||
wantErr: true,
|
|
||||||
setEnv: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Expired Token",
|
|
||||||
args: args{
|
|
||||||
tokenString: func() string {
|
|
||||||
claims := &Claims{
|
|
||||||
Username: "expireduser",
|
|
||||||
RegisteredClaims: jwt.RegisteredClaims{
|
|
||||||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(-24 * time.Hour)),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
|
||||||
tokenString, _ := token.SignedString([]byte(os.Getenv("SECRET")))
|
|
||||||
return tokenString
|
|
||||||
}(),
|
|
||||||
},
|
|
||||||
want: nil,
|
|
||||||
wantErr: true,
|
|
||||||
setEnv: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Without Secret",
|
|
||||||
args: args{
|
|
||||||
tokenString: "invalidTokenString",
|
|
||||||
},
|
|
||||||
want: nil,
|
|
||||||
wantErr: true,
|
|
||||||
setEnv: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
if tt.setEnv {
|
|
||||||
os.Setenv("SECRET", "dummy-secret") // Set the secret environment variable
|
|
||||||
} else {
|
|
||||||
os.Unsetenv("SECRET")
|
|
||||||
}
|
|
||||||
got, err := ValidateJWT(tt.args.tokenString)
|
|
||||||
if (err != nil) != tt.wantErr {
|
|
||||||
t.Errorf("ValidateJWT() error = %v, wantErr %v", err, tt.wantErr)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(got, tt.want) {
|
|
||||||
t.Errorf("ValidateJWT() = %v, want %v", got, tt.want)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -55,7 +55,7 @@ func Login(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
token, err := GenerateJWT(user.Username)
|
token, err := util.EncodeUserJWT(user.Username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
@@ -71,7 +71,7 @@ func VerifyToken(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := ValidateJWT(tokenString[7:])
|
_, err := util.DecodeJWT(tokenString[7:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "Invalid token", http.StatusUnauthorized)
|
http.Error(w, "Invalid token", http.StatusUnauthorized)
|
||||||
return
|
return
|
||||||
@@ -121,6 +121,61 @@ func GetEvents(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Agents ---------------------------------------------------------------------
|
||||||
|
|
||||||
|
// GetAgents returns all agents
|
||||||
|
func GetAgents(w http.ResponseWriter, r *http.Request) {
|
||||||
|
agents, err := db.Query.ListAgents(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Failed to get agents", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
writeJSON(w, agents)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAgent returns an agent
|
||||||
|
func GetAgent(w http.ResponseWriter, r *http.Request) {
|
||||||
|
agent, err := db.Query.GetAgentByID(context.Background(), r.PathValue("id"))
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Failed to get agent", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
writeJSON(w, agent)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteAgent deletes an agent
|
||||||
|
func DeleteAgent(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if err := db.Query.DeleteAgentByID(context.Background(), r.PathValue("id")); err != nil {
|
||||||
|
http.Error(w, "Failed to delete agent", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAgentToken returns an agent token
|
||||||
|
func GetAgentToken(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var data struct {
|
||||||
|
ServerURL string `json:"url"`
|
||||||
|
}
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if data.ServerURL == "" {
|
||||||
|
http.Error(w, "Server URL cannot be empty", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
token, err := util.EncodeAgentJWT(data.ServerURL)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
writeJSON(w, map[string]string{"token": token})
|
||||||
|
}
|
||||||
|
|
||||||
// Profiles -------------------------------------------------------------------
|
// Profiles -------------------------------------------------------------------
|
||||||
|
|
||||||
// GetProfiles returns all profiles but without the dynamic data
|
// GetProfiles returns all profiles but without the dynamic data
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/MizuchiLabs/mantrae/internal/db"
|
"github.com/MizuchiLabs/mantrae/internal/db"
|
||||||
|
"github.com/MizuchiLabs/mantrae/pkg/util"
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -152,7 +153,7 @@ func JWT(next http.HandlerFunc) http.HandlerFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Validate JWT token
|
// Validate JWT token
|
||||||
claims, err := ValidateJWT(token)
|
claims, err := util.DecodeJWT(token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -47,7 +47,13 @@ func Routes(useAuth bool) http.Handler {
|
|||||||
mux.HandleFunc("GET /api/settings/{key}", JWT(GetSetting))
|
mux.HandleFunc("GET /api/settings/{key}", JWT(GetSetting))
|
||||||
mux.HandleFunc("PUT /api/settings", JWT(UpdateSetting))
|
mux.HandleFunc("PUT /api/settings", JWT(UpdateSetting))
|
||||||
|
|
||||||
|
mux.HandleFunc("GET /api/agent", JWT(GetAgents))
|
||||||
|
mux.HandleFunc("GET /api/agent/{id}", JWT(GetAgent))
|
||||||
|
mux.HandleFunc("DELETE /api/agent", JWT(DeleteAgent))
|
||||||
|
mux.HandleFunc("GET /api/agent/token", JWT(GetAgentToken))
|
||||||
|
|
||||||
mux.HandleFunc("GET /api/ip/{id}", JWT(GetPublicIP))
|
mux.HandleFunc("GET /api/ip/{id}", JWT(GetPublicIP))
|
||||||
|
|
||||||
mux.HandleFunc("GET /api/backup", JWT(DownloadBackup))
|
mux.HandleFunc("GET /api/backup", JWT(DownloadBackup))
|
||||||
mux.HandleFunc("POST /api/restore", JWT(UploadBackup))
|
mux.HandleFunc("POST /api/restore", JWT(UploadBackup))
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,12 @@ type Flags struct {
|
|||||||
UseAuth bool
|
UseAuth bool
|
||||||
Update bool
|
Update bool
|
||||||
Reset bool
|
Reset bool
|
||||||
|
Agent AgentFlags
|
||||||
|
}
|
||||||
|
|
||||||
|
type AgentFlags struct {
|
||||||
|
Enabled bool
|
||||||
|
Port string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Flags) Parse() error {
|
func (f *Flags) Parse() error {
|
||||||
@@ -37,11 +43,15 @@ func (f *Flags) Parse() error {
|
|||||||
)
|
)
|
||||||
flag.StringVar(&f.Username, "username", "", "Specify the username for the Traefik instance")
|
flag.StringVar(&f.Username, "username", "", "Specify the username for the Traefik instance")
|
||||||
flag.StringVar(&f.Password, "password", "", "Specify the password for the Traefik instance")
|
flag.StringVar(&f.Password, "password", "", "Specify the password for the Traefik instance")
|
||||||
flag.StringVar(&f.Config, "config", "", "Specify the path to the database location")
|
flag.StringVar(&f.Config, "config", "", "Specify the path to the config location")
|
||||||
flag.BoolVar(&f.UseAuth, "auth", false, "Use basic authentication for the profile endpoint")
|
flag.BoolVar(&f.UseAuth, "auth", false, "Use basic authentication for the profile endpoint")
|
||||||
flag.BoolVar(&f.Update, "update", false, "Update the application")
|
flag.BoolVar(&f.Update, "update", false, "Update the application")
|
||||||
flag.BoolVar(&f.Reset, "reset", false, "Reset the default admin password")
|
flag.BoolVar(&f.Reset, "reset", false, "Reset the default admin password")
|
||||||
|
|
||||||
|
// Agent flags
|
||||||
|
flag.BoolVar(&f.Agent.Enabled, "agent.enabled", true, "Enable the agent server")
|
||||||
|
flag.StringVar(&f.Agent.Port, "agent.port", "8090", "Port to listen on for agents")
|
||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError)
|
flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError)
|
||||||
|
|
||||||
@@ -49,6 +59,9 @@ func (f *Flags) Parse() error {
|
|||||||
fmt.Println(util.Version)
|
fmt.Println(util.Version)
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
if f.Config != "" {
|
||||||
|
util.MainDir = f.Config
|
||||||
|
}
|
||||||
if err := SetDefaultAdminUser(); err != nil {
|
if err := SetDefaultAdminUser(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -66,9 +79,6 @@ func (f *Flags) Parse() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if f.Config != "" {
|
|
||||||
util.MainDir = f.Config
|
|
||||||
}
|
|
||||||
|
|
||||||
util.UpdateSelf(f.Update)
|
util.UpdateSelf(f.Update)
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,9 @@ func New(db DBTX) *Queries {
|
|||||||
func Prepare(ctx context.Context, db DBTX) (*Queries, error) {
|
func Prepare(ctx context.Context, db DBTX) (*Queries, error) {
|
||||||
q := Queries{db: db}
|
q := Queries{db: db}
|
||||||
var err error
|
var err error
|
||||||
|
if q.createAgentStmt, err = db.PrepareContext(ctx, createAgent); err != nil {
|
||||||
|
return nil, fmt.Errorf("error preparing query CreateAgent: %w", err)
|
||||||
|
}
|
||||||
if q.createConfigStmt, err = db.PrepareContext(ctx, createConfig); err != nil {
|
if q.createConfigStmt, err = db.PrepareContext(ctx, createConfig); err != nil {
|
||||||
return nil, fmt.Errorf("error preparing query CreateConfig: %w", err)
|
return nil, fmt.Errorf("error preparing query CreateConfig: %w", err)
|
||||||
}
|
}
|
||||||
@@ -39,6 +42,12 @@ func Prepare(ctx context.Context, db DBTX) (*Queries, error) {
|
|||||||
if q.createUserStmt, err = db.PrepareContext(ctx, createUser); err != nil {
|
if q.createUserStmt, err = db.PrepareContext(ctx, createUser); err != nil {
|
||||||
return nil, fmt.Errorf("error preparing query CreateUser: %w", err)
|
return nil, fmt.Errorf("error preparing query CreateUser: %w", err)
|
||||||
}
|
}
|
||||||
|
if q.deleteAgentByHostnameStmt, err = db.PrepareContext(ctx, deleteAgentByHostname); err != nil {
|
||||||
|
return nil, fmt.Errorf("error preparing query DeleteAgentByHostname: %w", err)
|
||||||
|
}
|
||||||
|
if q.deleteAgentByIDStmt, err = db.PrepareContext(ctx, deleteAgentByID); err != nil {
|
||||||
|
return nil, fmt.Errorf("error preparing query DeleteAgentByID: %w", err)
|
||||||
|
}
|
||||||
if q.deleteConfigByProfileIDStmt, err = db.PrepareContext(ctx, deleteConfigByProfileID); err != nil {
|
if q.deleteConfigByProfileIDStmt, err = db.PrepareContext(ctx, deleteConfigByProfileID); err != nil {
|
||||||
return nil, fmt.Errorf("error preparing query DeleteConfigByProfileID: %w", err)
|
return nil, fmt.Errorf("error preparing query DeleteConfigByProfileID: %w", err)
|
||||||
}
|
}
|
||||||
@@ -57,6 +66,9 @@ func Prepare(ctx context.Context, db DBTX) (*Queries, error) {
|
|||||||
if q.deleteProviderByNameStmt, err = db.PrepareContext(ctx, deleteProviderByName); err != nil {
|
if q.deleteProviderByNameStmt, err = db.PrepareContext(ctx, deleteProviderByName); err != nil {
|
||||||
return nil, fmt.Errorf("error preparing query DeleteProviderByName: %w", err)
|
return nil, fmt.Errorf("error preparing query DeleteProviderByName: %w", err)
|
||||||
}
|
}
|
||||||
|
if q.deleteSettingByIDStmt, err = db.PrepareContext(ctx, deleteSettingByID); err != nil {
|
||||||
|
return nil, fmt.Errorf("error preparing query DeleteSettingByID: %w", err)
|
||||||
|
}
|
||||||
if q.deleteSettingByKeyStmt, err = db.PrepareContext(ctx, deleteSettingByKey); err != nil {
|
if q.deleteSettingByKeyStmt, err = db.PrepareContext(ctx, deleteSettingByKey); err != nil {
|
||||||
return nil, fmt.Errorf("error preparing query DeleteSettingByKey: %w", err)
|
return nil, fmt.Errorf("error preparing query DeleteSettingByKey: %w", err)
|
||||||
}
|
}
|
||||||
@@ -66,6 +78,12 @@ func Prepare(ctx context.Context, db DBTX) (*Queries, error) {
|
|||||||
if q.deleteUserByUsernameStmt, err = db.PrepareContext(ctx, deleteUserByUsername); err != nil {
|
if q.deleteUserByUsernameStmt, err = db.PrepareContext(ctx, deleteUserByUsername); err != nil {
|
||||||
return nil, fmt.Errorf("error preparing query DeleteUserByUsername: %w", err)
|
return nil, fmt.Errorf("error preparing query DeleteUserByUsername: %w", err)
|
||||||
}
|
}
|
||||||
|
if q.getAgentByHostnameStmt, err = db.PrepareContext(ctx, getAgentByHostname); err != nil {
|
||||||
|
return nil, fmt.Errorf("error preparing query GetAgentByHostname: %w", err)
|
||||||
|
}
|
||||||
|
if q.getAgentByIDStmt, err = db.PrepareContext(ctx, getAgentByID); err != nil {
|
||||||
|
return nil, fmt.Errorf("error preparing query GetAgentByID: %w", err)
|
||||||
|
}
|
||||||
if q.getConfigByProfileIDStmt, err = db.PrepareContext(ctx, getConfigByProfileID); err != nil {
|
if q.getConfigByProfileIDStmt, err = db.PrepareContext(ctx, getConfigByProfileID); err != nil {
|
||||||
return nil, fmt.Errorf("error preparing query GetConfigByProfileID: %w", err)
|
return nil, fmt.Errorf("error preparing query GetConfigByProfileID: %w", err)
|
||||||
}
|
}
|
||||||
@@ -93,6 +111,9 @@ func Prepare(ctx context.Context, db DBTX) (*Queries, error) {
|
|||||||
if q.getUserByUsernameStmt, err = db.PrepareContext(ctx, getUserByUsername); err != nil {
|
if q.getUserByUsernameStmt, err = db.PrepareContext(ctx, getUserByUsername); err != nil {
|
||||||
return nil, fmt.Errorf("error preparing query GetUserByUsername: %w", err)
|
return nil, fmt.Errorf("error preparing query GetUserByUsername: %w", err)
|
||||||
}
|
}
|
||||||
|
if q.listAgentsStmt, err = db.PrepareContext(ctx, listAgents); err != nil {
|
||||||
|
return nil, fmt.Errorf("error preparing query ListAgents: %w", err)
|
||||||
|
}
|
||||||
if q.listConfigsStmt, err = db.PrepareContext(ctx, listConfigs); err != nil {
|
if q.listConfigsStmt, err = db.PrepareContext(ctx, listConfigs); err != nil {
|
||||||
return nil, fmt.Errorf("error preparing query ListConfigs: %w", err)
|
return nil, fmt.Errorf("error preparing query ListConfigs: %w", err)
|
||||||
}
|
}
|
||||||
@@ -108,6 +129,9 @@ func Prepare(ctx context.Context, db DBTX) (*Queries, error) {
|
|||||||
if q.listUsersStmt, err = db.PrepareContext(ctx, listUsers); err != nil {
|
if q.listUsersStmt, err = db.PrepareContext(ctx, listUsers); err != nil {
|
||||||
return nil, fmt.Errorf("error preparing query ListUsers: %w", err)
|
return nil, fmt.Errorf("error preparing query ListUsers: %w", err)
|
||||||
}
|
}
|
||||||
|
if q.updateAgentStmt, err = db.PrepareContext(ctx, updateAgent); err != nil {
|
||||||
|
return nil, fmt.Errorf("error preparing query UpdateAgent: %w", err)
|
||||||
|
}
|
||||||
if q.updateConfigStmt, err = db.PrepareContext(ctx, updateConfig); err != nil {
|
if q.updateConfigStmt, err = db.PrepareContext(ctx, updateConfig); err != nil {
|
||||||
return nil, fmt.Errorf("error preparing query UpdateConfig: %w", err)
|
return nil, fmt.Errorf("error preparing query UpdateConfig: %w", err)
|
||||||
}
|
}
|
||||||
@@ -123,6 +147,9 @@ func Prepare(ctx context.Context, db DBTX) (*Queries, error) {
|
|||||||
if q.updateUserStmt, err = db.PrepareContext(ctx, updateUser); err != nil {
|
if q.updateUserStmt, err = db.PrepareContext(ctx, updateUser); err != nil {
|
||||||
return nil, fmt.Errorf("error preparing query UpdateUser: %w", err)
|
return nil, fmt.Errorf("error preparing query UpdateUser: %w", err)
|
||||||
}
|
}
|
||||||
|
if q.upsertAgentStmt, err = db.PrepareContext(ctx, upsertAgent); err != nil {
|
||||||
|
return nil, fmt.Errorf("error preparing query UpsertAgent: %w", err)
|
||||||
|
}
|
||||||
if q.upsertProfileStmt, err = db.PrepareContext(ctx, upsertProfile); err != nil {
|
if q.upsertProfileStmt, err = db.PrepareContext(ctx, upsertProfile); err != nil {
|
||||||
return nil, fmt.Errorf("error preparing query UpsertProfile: %w", err)
|
return nil, fmt.Errorf("error preparing query UpsertProfile: %w", err)
|
||||||
}
|
}
|
||||||
@@ -140,6 +167,11 @@ func Prepare(ctx context.Context, db DBTX) (*Queries, error) {
|
|||||||
|
|
||||||
func (q *Queries) Close() error {
|
func (q *Queries) Close() error {
|
||||||
var err error
|
var err error
|
||||||
|
if q.createAgentStmt != nil {
|
||||||
|
if cerr := q.createAgentStmt.Close(); cerr != nil {
|
||||||
|
err = fmt.Errorf("error closing createAgentStmt: %w", cerr)
|
||||||
|
}
|
||||||
|
}
|
||||||
if q.createConfigStmt != nil {
|
if q.createConfigStmt != nil {
|
||||||
if cerr := q.createConfigStmt.Close(); cerr != nil {
|
if cerr := q.createConfigStmt.Close(); cerr != nil {
|
||||||
err = fmt.Errorf("error closing createConfigStmt: %w", cerr)
|
err = fmt.Errorf("error closing createConfigStmt: %w", cerr)
|
||||||
@@ -165,6 +197,16 @@ func (q *Queries) Close() error {
|
|||||||
err = fmt.Errorf("error closing createUserStmt: %w", cerr)
|
err = fmt.Errorf("error closing createUserStmt: %w", cerr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if q.deleteAgentByHostnameStmt != nil {
|
||||||
|
if cerr := q.deleteAgentByHostnameStmt.Close(); cerr != nil {
|
||||||
|
err = fmt.Errorf("error closing deleteAgentByHostnameStmt: %w", cerr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if q.deleteAgentByIDStmt != nil {
|
||||||
|
if cerr := q.deleteAgentByIDStmt.Close(); cerr != nil {
|
||||||
|
err = fmt.Errorf("error closing deleteAgentByIDStmt: %w", cerr)
|
||||||
|
}
|
||||||
|
}
|
||||||
if q.deleteConfigByProfileIDStmt != nil {
|
if q.deleteConfigByProfileIDStmt != nil {
|
||||||
if cerr := q.deleteConfigByProfileIDStmt.Close(); cerr != nil {
|
if cerr := q.deleteConfigByProfileIDStmt.Close(); cerr != nil {
|
||||||
err = fmt.Errorf("error closing deleteConfigByProfileIDStmt: %w", cerr)
|
err = fmt.Errorf("error closing deleteConfigByProfileIDStmt: %w", cerr)
|
||||||
@@ -195,6 +237,11 @@ func (q *Queries) Close() error {
|
|||||||
err = fmt.Errorf("error closing deleteProviderByNameStmt: %w", cerr)
|
err = fmt.Errorf("error closing deleteProviderByNameStmt: %w", cerr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if q.deleteSettingByIDStmt != nil {
|
||||||
|
if cerr := q.deleteSettingByIDStmt.Close(); cerr != nil {
|
||||||
|
err = fmt.Errorf("error closing deleteSettingByIDStmt: %w", cerr)
|
||||||
|
}
|
||||||
|
}
|
||||||
if q.deleteSettingByKeyStmt != nil {
|
if q.deleteSettingByKeyStmt != nil {
|
||||||
if cerr := q.deleteSettingByKeyStmt.Close(); cerr != nil {
|
if cerr := q.deleteSettingByKeyStmt.Close(); cerr != nil {
|
||||||
err = fmt.Errorf("error closing deleteSettingByKeyStmt: %w", cerr)
|
err = fmt.Errorf("error closing deleteSettingByKeyStmt: %w", cerr)
|
||||||
@@ -210,6 +257,16 @@ func (q *Queries) Close() error {
|
|||||||
err = fmt.Errorf("error closing deleteUserByUsernameStmt: %w", cerr)
|
err = fmt.Errorf("error closing deleteUserByUsernameStmt: %w", cerr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if q.getAgentByHostnameStmt != nil {
|
||||||
|
if cerr := q.getAgentByHostnameStmt.Close(); cerr != nil {
|
||||||
|
err = fmt.Errorf("error closing getAgentByHostnameStmt: %w", cerr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if q.getAgentByIDStmt != nil {
|
||||||
|
if cerr := q.getAgentByIDStmt.Close(); cerr != nil {
|
||||||
|
err = fmt.Errorf("error closing getAgentByIDStmt: %w", cerr)
|
||||||
|
}
|
||||||
|
}
|
||||||
if q.getConfigByProfileIDStmt != nil {
|
if q.getConfigByProfileIDStmt != nil {
|
||||||
if cerr := q.getConfigByProfileIDStmt.Close(); cerr != nil {
|
if cerr := q.getConfigByProfileIDStmt.Close(); cerr != nil {
|
||||||
err = fmt.Errorf("error closing getConfigByProfileIDStmt: %w", cerr)
|
err = fmt.Errorf("error closing getConfigByProfileIDStmt: %w", cerr)
|
||||||
@@ -255,6 +312,11 @@ func (q *Queries) Close() error {
|
|||||||
err = fmt.Errorf("error closing getUserByUsernameStmt: %w", cerr)
|
err = fmt.Errorf("error closing getUserByUsernameStmt: %w", cerr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if q.listAgentsStmt != nil {
|
||||||
|
if cerr := q.listAgentsStmt.Close(); cerr != nil {
|
||||||
|
err = fmt.Errorf("error closing listAgentsStmt: %w", cerr)
|
||||||
|
}
|
||||||
|
}
|
||||||
if q.listConfigsStmt != nil {
|
if q.listConfigsStmt != nil {
|
||||||
if cerr := q.listConfigsStmt.Close(); cerr != nil {
|
if cerr := q.listConfigsStmt.Close(); cerr != nil {
|
||||||
err = fmt.Errorf("error closing listConfigsStmt: %w", cerr)
|
err = fmt.Errorf("error closing listConfigsStmt: %w", cerr)
|
||||||
@@ -280,6 +342,11 @@ func (q *Queries) Close() error {
|
|||||||
err = fmt.Errorf("error closing listUsersStmt: %w", cerr)
|
err = fmt.Errorf("error closing listUsersStmt: %w", cerr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if q.updateAgentStmt != nil {
|
||||||
|
if cerr := q.updateAgentStmt.Close(); cerr != nil {
|
||||||
|
err = fmt.Errorf("error closing updateAgentStmt: %w", cerr)
|
||||||
|
}
|
||||||
|
}
|
||||||
if q.updateConfigStmt != nil {
|
if q.updateConfigStmt != nil {
|
||||||
if cerr := q.updateConfigStmt.Close(); cerr != nil {
|
if cerr := q.updateConfigStmt.Close(); cerr != nil {
|
||||||
err = fmt.Errorf("error closing updateConfigStmt: %w", cerr)
|
err = fmt.Errorf("error closing updateConfigStmt: %w", cerr)
|
||||||
@@ -305,6 +372,11 @@ func (q *Queries) Close() error {
|
|||||||
err = fmt.Errorf("error closing updateUserStmt: %w", cerr)
|
err = fmt.Errorf("error closing updateUserStmt: %w", cerr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if q.upsertAgentStmt != nil {
|
||||||
|
if cerr := q.upsertAgentStmt.Close(); cerr != nil {
|
||||||
|
err = fmt.Errorf("error closing upsertAgentStmt: %w", cerr)
|
||||||
|
}
|
||||||
|
}
|
||||||
if q.upsertProfileStmt != nil {
|
if q.upsertProfileStmt != nil {
|
||||||
if cerr := q.upsertProfileStmt.Close(); cerr != nil {
|
if cerr := q.upsertProfileStmt.Close(); cerr != nil {
|
||||||
err = fmt.Errorf("error closing upsertProfileStmt: %w", cerr)
|
err = fmt.Errorf("error closing upsertProfileStmt: %w", cerr)
|
||||||
@@ -364,20 +436,26 @@ func (q *Queries) queryRow(ctx context.Context, stmt *sql.Stmt, query string, ar
|
|||||||
type Queries struct {
|
type Queries struct {
|
||||||
db DBTX
|
db DBTX
|
||||||
tx *sql.Tx
|
tx *sql.Tx
|
||||||
|
createAgentStmt *sql.Stmt
|
||||||
createConfigStmt *sql.Stmt
|
createConfigStmt *sql.Stmt
|
||||||
createProfileStmt *sql.Stmt
|
createProfileStmt *sql.Stmt
|
||||||
createProviderStmt *sql.Stmt
|
createProviderStmt *sql.Stmt
|
||||||
createSettingStmt *sql.Stmt
|
createSettingStmt *sql.Stmt
|
||||||
createUserStmt *sql.Stmt
|
createUserStmt *sql.Stmt
|
||||||
|
deleteAgentByHostnameStmt *sql.Stmt
|
||||||
|
deleteAgentByIDStmt *sql.Stmt
|
||||||
deleteConfigByProfileIDStmt *sql.Stmt
|
deleteConfigByProfileIDStmt *sql.Stmt
|
||||||
deleteConfigByProfileNameStmt *sql.Stmt
|
deleteConfigByProfileNameStmt *sql.Stmt
|
||||||
deleteProfileByIDStmt *sql.Stmt
|
deleteProfileByIDStmt *sql.Stmt
|
||||||
deleteProfileByNameStmt *sql.Stmt
|
deleteProfileByNameStmt *sql.Stmt
|
||||||
deleteProviderByIDStmt *sql.Stmt
|
deleteProviderByIDStmt *sql.Stmt
|
||||||
deleteProviderByNameStmt *sql.Stmt
|
deleteProviderByNameStmt *sql.Stmt
|
||||||
|
deleteSettingByIDStmt *sql.Stmt
|
||||||
deleteSettingByKeyStmt *sql.Stmt
|
deleteSettingByKeyStmt *sql.Stmt
|
||||||
deleteUserByIDStmt *sql.Stmt
|
deleteUserByIDStmt *sql.Stmt
|
||||||
deleteUserByUsernameStmt *sql.Stmt
|
deleteUserByUsernameStmt *sql.Stmt
|
||||||
|
getAgentByHostnameStmt *sql.Stmt
|
||||||
|
getAgentByIDStmt *sql.Stmt
|
||||||
getConfigByProfileIDStmt *sql.Stmt
|
getConfigByProfileIDStmt *sql.Stmt
|
||||||
getConfigByProfileNameStmt *sql.Stmt
|
getConfigByProfileNameStmt *sql.Stmt
|
||||||
getProfileByIDStmt *sql.Stmt
|
getProfileByIDStmt *sql.Stmt
|
||||||
@@ -387,16 +465,19 @@ type Queries struct {
|
|||||||
getSettingByKeyStmt *sql.Stmt
|
getSettingByKeyStmt *sql.Stmt
|
||||||
getUserByIDStmt *sql.Stmt
|
getUserByIDStmt *sql.Stmt
|
||||||
getUserByUsernameStmt *sql.Stmt
|
getUserByUsernameStmt *sql.Stmt
|
||||||
|
listAgentsStmt *sql.Stmt
|
||||||
listConfigsStmt *sql.Stmt
|
listConfigsStmt *sql.Stmt
|
||||||
listProfilesStmt *sql.Stmt
|
listProfilesStmt *sql.Stmt
|
||||||
listProvidersStmt *sql.Stmt
|
listProvidersStmt *sql.Stmt
|
||||||
listSettingsStmt *sql.Stmt
|
listSettingsStmt *sql.Stmt
|
||||||
listUsersStmt *sql.Stmt
|
listUsersStmt *sql.Stmt
|
||||||
|
updateAgentStmt *sql.Stmt
|
||||||
updateConfigStmt *sql.Stmt
|
updateConfigStmt *sql.Stmt
|
||||||
updateProfileStmt *sql.Stmt
|
updateProfileStmt *sql.Stmt
|
||||||
updateProviderStmt *sql.Stmt
|
updateProviderStmt *sql.Stmt
|
||||||
updateSettingStmt *sql.Stmt
|
updateSettingStmt *sql.Stmt
|
||||||
updateUserStmt *sql.Stmt
|
updateUserStmt *sql.Stmt
|
||||||
|
upsertAgentStmt *sql.Stmt
|
||||||
upsertProfileStmt *sql.Stmt
|
upsertProfileStmt *sql.Stmt
|
||||||
upsertProviderStmt *sql.Stmt
|
upsertProviderStmt *sql.Stmt
|
||||||
upsertSettingStmt *sql.Stmt
|
upsertSettingStmt *sql.Stmt
|
||||||
@@ -407,20 +488,26 @@ func (q *Queries) WithTx(tx *sql.Tx) *Queries {
|
|||||||
return &Queries{
|
return &Queries{
|
||||||
db: tx,
|
db: tx,
|
||||||
tx: tx,
|
tx: tx,
|
||||||
|
createAgentStmt: q.createAgentStmt,
|
||||||
createConfigStmt: q.createConfigStmt,
|
createConfigStmt: q.createConfigStmt,
|
||||||
createProfileStmt: q.createProfileStmt,
|
createProfileStmt: q.createProfileStmt,
|
||||||
createProviderStmt: q.createProviderStmt,
|
createProviderStmt: q.createProviderStmt,
|
||||||
createSettingStmt: q.createSettingStmt,
|
createSettingStmt: q.createSettingStmt,
|
||||||
createUserStmt: q.createUserStmt,
|
createUserStmt: q.createUserStmt,
|
||||||
|
deleteAgentByHostnameStmt: q.deleteAgentByHostnameStmt,
|
||||||
|
deleteAgentByIDStmt: q.deleteAgentByIDStmt,
|
||||||
deleteConfigByProfileIDStmt: q.deleteConfigByProfileIDStmt,
|
deleteConfigByProfileIDStmt: q.deleteConfigByProfileIDStmt,
|
||||||
deleteConfigByProfileNameStmt: q.deleteConfigByProfileNameStmt,
|
deleteConfigByProfileNameStmt: q.deleteConfigByProfileNameStmt,
|
||||||
deleteProfileByIDStmt: q.deleteProfileByIDStmt,
|
deleteProfileByIDStmt: q.deleteProfileByIDStmt,
|
||||||
deleteProfileByNameStmt: q.deleteProfileByNameStmt,
|
deleteProfileByNameStmt: q.deleteProfileByNameStmt,
|
||||||
deleteProviderByIDStmt: q.deleteProviderByIDStmt,
|
deleteProviderByIDStmt: q.deleteProviderByIDStmt,
|
||||||
deleteProviderByNameStmt: q.deleteProviderByNameStmt,
|
deleteProviderByNameStmt: q.deleteProviderByNameStmt,
|
||||||
|
deleteSettingByIDStmt: q.deleteSettingByIDStmt,
|
||||||
deleteSettingByKeyStmt: q.deleteSettingByKeyStmt,
|
deleteSettingByKeyStmt: q.deleteSettingByKeyStmt,
|
||||||
deleteUserByIDStmt: q.deleteUserByIDStmt,
|
deleteUserByIDStmt: q.deleteUserByIDStmt,
|
||||||
deleteUserByUsernameStmt: q.deleteUserByUsernameStmt,
|
deleteUserByUsernameStmt: q.deleteUserByUsernameStmt,
|
||||||
|
getAgentByHostnameStmt: q.getAgentByHostnameStmt,
|
||||||
|
getAgentByIDStmt: q.getAgentByIDStmt,
|
||||||
getConfigByProfileIDStmt: q.getConfigByProfileIDStmt,
|
getConfigByProfileIDStmt: q.getConfigByProfileIDStmt,
|
||||||
getConfigByProfileNameStmt: q.getConfigByProfileNameStmt,
|
getConfigByProfileNameStmt: q.getConfigByProfileNameStmt,
|
||||||
getProfileByIDStmt: q.getProfileByIDStmt,
|
getProfileByIDStmt: q.getProfileByIDStmt,
|
||||||
@@ -430,16 +517,19 @@ func (q *Queries) WithTx(tx *sql.Tx) *Queries {
|
|||||||
getSettingByKeyStmt: q.getSettingByKeyStmt,
|
getSettingByKeyStmt: q.getSettingByKeyStmt,
|
||||||
getUserByIDStmt: q.getUserByIDStmt,
|
getUserByIDStmt: q.getUserByIDStmt,
|
||||||
getUserByUsernameStmt: q.getUserByUsernameStmt,
|
getUserByUsernameStmt: q.getUserByUsernameStmt,
|
||||||
|
listAgentsStmt: q.listAgentsStmt,
|
||||||
listConfigsStmt: q.listConfigsStmt,
|
listConfigsStmt: q.listConfigsStmt,
|
||||||
listProfilesStmt: q.listProfilesStmt,
|
listProfilesStmt: q.listProfilesStmt,
|
||||||
listProvidersStmt: q.listProvidersStmt,
|
listProvidersStmt: q.listProvidersStmt,
|
||||||
listSettingsStmt: q.listSettingsStmt,
|
listSettingsStmt: q.listSettingsStmt,
|
||||||
listUsersStmt: q.listUsersStmt,
|
listUsersStmt: q.listUsersStmt,
|
||||||
|
updateAgentStmt: q.updateAgentStmt,
|
||||||
updateConfigStmt: q.updateConfigStmt,
|
updateConfigStmt: q.updateConfigStmt,
|
||||||
updateProfileStmt: q.updateProfileStmt,
|
updateProfileStmt: q.updateProfileStmt,
|
||||||
updateProviderStmt: q.updateProviderStmt,
|
updateProviderStmt: q.updateProviderStmt,
|
||||||
updateSettingStmt: q.updateSettingStmt,
|
updateSettingStmt: q.updateSettingStmt,
|
||||||
updateUserStmt: q.updateUserStmt,
|
updateUserStmt: q.updateUserStmt,
|
||||||
|
upsertAgentStmt: q.upsertAgentStmt,
|
||||||
upsertProfileStmt: q.upsertProfileStmt,
|
upsertProfileStmt: q.upsertProfileStmt,
|
||||||
upsertProviderStmt: q.upsertProviderStmt,
|
upsertProviderStmt: q.upsertProviderStmt,
|
||||||
upsertSettingStmt: q.upsertSettingStmt,
|
upsertSettingStmt: q.upsertSettingStmt,
|
||||||
|
|||||||
@@ -45,6 +45,15 @@ CREATE TABLE settings (
|
|||||||
value TEXT NOT NULL
|
value TEXT NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE TABLE agents (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
hostname VARCHAR(100) NOT NULL,
|
||||||
|
public_ip TEXT,
|
||||||
|
private_ips JSONB,
|
||||||
|
containers JSONB,
|
||||||
|
last_seen DATETIME
|
||||||
|
);
|
||||||
|
|
||||||
-- +goose StatementBegin
|
-- +goose StatementBegin
|
||||||
CREATE TRIGGER add_profile_config AFTER INSERT ON profiles FOR EACH ROW BEGIN
|
CREATE TRIGGER add_profile_config AFTER INSERT ON profiles FOR EACH ROW BEGIN
|
||||||
INSERT INTO
|
INSERT INTO
|
||||||
@@ -89,6 +98,10 @@ DROP TABLE users;
|
|||||||
|
|
||||||
DROP TABLE settings;
|
DROP TABLE settings;
|
||||||
|
|
||||||
|
DROP TABLE agents;
|
||||||
|
|
||||||
|
DROP TABLE containers;
|
||||||
|
|
||||||
DROP TRIGGER add_profile_config;
|
DROP TRIGGER add_profile_config;
|
||||||
|
|
||||||
DROP TRIGGER ensure_single_active_insert;
|
DROP TRIGGER ensure_single_active_insert;
|
||||||
|
|||||||
@@ -4,6 +4,19 @@
|
|||||||
|
|
||||||
package db
|
package db
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Agent struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Hostname string `json:"hostname"`
|
||||||
|
PublicIp *string `json:"public_ip"`
|
||||||
|
PrivateIps interface{} `json:"private_ips"`
|
||||||
|
Containers interface{} `json:"containers"`
|
||||||
|
LastSeen *time.Time `json:"last_seen"`
|
||||||
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
ProfileID int64 `json:"profile_id"`
|
ProfileID int64 `json:"profile_id"`
|
||||||
Overview interface{} `json:"overview"`
|
Overview interface{} `json:"overview"`
|
||||||
|
|||||||
@@ -9,20 +9,26 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Querier interface {
|
type Querier interface {
|
||||||
|
CreateAgent(ctx context.Context, arg CreateAgentParams) (Agent, error)
|
||||||
CreateConfig(ctx context.Context, arg CreateConfigParams) (Config, error)
|
CreateConfig(ctx context.Context, arg CreateConfigParams) (Config, error)
|
||||||
CreateProfile(ctx context.Context, arg CreateProfileParams) (Profile, error)
|
CreateProfile(ctx context.Context, arg CreateProfileParams) (Profile, error)
|
||||||
CreateProvider(ctx context.Context, arg CreateProviderParams) (Provider, error)
|
CreateProvider(ctx context.Context, arg CreateProviderParams) (Provider, error)
|
||||||
CreateSetting(ctx context.Context, arg CreateSettingParams) (Setting, error)
|
CreateSetting(ctx context.Context, arg CreateSettingParams) (Setting, error)
|
||||||
CreateUser(ctx context.Context, arg CreateUserParams) (User, error)
|
CreateUser(ctx context.Context, arg CreateUserParams) (User, error)
|
||||||
|
DeleteAgentByHostname(ctx context.Context, hostname string) error
|
||||||
|
DeleteAgentByID(ctx context.Context, id string) error
|
||||||
DeleteConfigByProfileID(ctx context.Context, profileID int64) error
|
DeleteConfigByProfileID(ctx context.Context, profileID int64) error
|
||||||
DeleteConfigByProfileName(ctx context.Context, name string) error
|
DeleteConfigByProfileName(ctx context.Context, name string) error
|
||||||
DeleteProfileByID(ctx context.Context, id int64) error
|
DeleteProfileByID(ctx context.Context, id int64) error
|
||||||
DeleteProfileByName(ctx context.Context, name string) error
|
DeleteProfileByName(ctx context.Context, name string) error
|
||||||
DeleteProviderByID(ctx context.Context, id int64) error
|
DeleteProviderByID(ctx context.Context, id int64) error
|
||||||
DeleteProviderByName(ctx context.Context, name string) error
|
DeleteProviderByName(ctx context.Context, name string) error
|
||||||
|
DeleteSettingByID(ctx context.Context, id int64) error
|
||||||
DeleteSettingByKey(ctx context.Context, key string) error
|
DeleteSettingByKey(ctx context.Context, key string) error
|
||||||
DeleteUserByID(ctx context.Context, id int64) error
|
DeleteUserByID(ctx context.Context, id int64) error
|
||||||
DeleteUserByUsername(ctx context.Context, username string) error
|
DeleteUserByUsername(ctx context.Context, username string) error
|
||||||
|
GetAgentByHostname(ctx context.Context, hostname string) (Agent, error)
|
||||||
|
GetAgentByID(ctx context.Context, id string) (Agent, error)
|
||||||
GetConfigByProfileID(ctx context.Context, profileID int64) (Config, error)
|
GetConfigByProfileID(ctx context.Context, profileID int64) (Config, error)
|
||||||
GetConfigByProfileName(ctx context.Context, name string) (Config, error)
|
GetConfigByProfileName(ctx context.Context, name string) (Config, error)
|
||||||
GetProfileByID(ctx context.Context, id int64) (Profile, error)
|
GetProfileByID(ctx context.Context, id int64) (Profile, error)
|
||||||
@@ -32,16 +38,19 @@ type Querier interface {
|
|||||||
GetSettingByKey(ctx context.Context, key string) (Setting, error)
|
GetSettingByKey(ctx context.Context, key string) (Setting, error)
|
||||||
GetUserByID(ctx context.Context, id int64) (User, error)
|
GetUserByID(ctx context.Context, id int64) (User, error)
|
||||||
GetUserByUsername(ctx context.Context, username string) (User, error)
|
GetUserByUsername(ctx context.Context, username string) (User, error)
|
||||||
|
ListAgents(ctx context.Context) ([]Agent, error)
|
||||||
ListConfigs(ctx context.Context) ([]Config, error)
|
ListConfigs(ctx context.Context) ([]Config, error)
|
||||||
ListProfiles(ctx context.Context) ([]Profile, error)
|
ListProfiles(ctx context.Context) ([]Profile, error)
|
||||||
ListProviders(ctx context.Context) ([]Provider, error)
|
ListProviders(ctx context.Context) ([]Provider, error)
|
||||||
ListSettings(ctx context.Context) ([]Setting, error)
|
ListSettings(ctx context.Context) ([]Setting, error)
|
||||||
ListUsers(ctx context.Context) ([]User, error)
|
ListUsers(ctx context.Context) ([]User, error)
|
||||||
|
UpdateAgent(ctx context.Context, arg UpdateAgentParams) (Agent, error)
|
||||||
UpdateConfig(ctx context.Context, arg UpdateConfigParams) (Config, error)
|
UpdateConfig(ctx context.Context, arg UpdateConfigParams) (Config, error)
|
||||||
UpdateProfile(ctx context.Context, arg UpdateProfileParams) (Profile, error)
|
UpdateProfile(ctx context.Context, arg UpdateProfileParams) (Profile, error)
|
||||||
UpdateProvider(ctx context.Context, arg UpdateProviderParams) (Provider, error)
|
UpdateProvider(ctx context.Context, arg UpdateProviderParams) (Provider, error)
|
||||||
UpdateSetting(ctx context.Context, arg UpdateSettingParams) (Setting, error)
|
UpdateSetting(ctx context.Context, arg UpdateSettingParams) (Setting, error)
|
||||||
UpdateUser(ctx context.Context, arg UpdateUserParams) (User, error)
|
UpdateUser(ctx context.Context, arg UpdateUserParams) (User, error)
|
||||||
|
UpsertAgent(ctx context.Context, arg UpsertAgentParams) (Agent, error)
|
||||||
UpsertProfile(ctx context.Context, arg UpsertProfileParams) (Profile, error)
|
UpsertProfile(ctx context.Context, arg UpsertProfileParams) (Profile, error)
|
||||||
UpsertProvider(ctx context.Context, arg UpsertProviderParams) (Provider, error)
|
UpsertProvider(ctx context.Context, arg UpsertProviderParams) (Provider, error)
|
||||||
UpsertSetting(ctx context.Context, arg UpsertSettingParams) (Setting, error)
|
UpsertSetting(ctx context.Context, arg UpsertSettingParams) (Setting, error)
|
||||||
|
|||||||
@@ -332,7 +332,92 @@ SET
|
|||||||
key = EXCLUDED.key,
|
key = EXCLUDED.key,
|
||||||
value = EXCLUDED.value RETURNING *;
|
value = EXCLUDED.value RETURNING *;
|
||||||
|
|
||||||
|
-- name: DeleteSettingByID :exec
|
||||||
|
DELETE FROM settings
|
||||||
|
WHERE
|
||||||
|
id = ?;
|
||||||
|
|
||||||
-- name: DeleteSettingByKey :exec
|
-- name: DeleteSettingByKey :exec
|
||||||
DELETE FROM settings
|
DELETE FROM settings
|
||||||
WHERE
|
WHERE
|
||||||
key = ?;
|
key = ?;
|
||||||
|
|
||||||
|
-- name: GetAgentByID :one
|
||||||
|
SELECT
|
||||||
|
*
|
||||||
|
FROM
|
||||||
|
agents
|
||||||
|
WHERE
|
||||||
|
id = ?
|
||||||
|
LIMIT
|
||||||
|
1;
|
||||||
|
|
||||||
|
-- name: GetAgentByHostname :one
|
||||||
|
SELECT
|
||||||
|
*
|
||||||
|
FROM
|
||||||
|
agents
|
||||||
|
WHERE
|
||||||
|
hostname = ?
|
||||||
|
LIMIT
|
||||||
|
1;
|
||||||
|
|
||||||
|
-- name: ListAgents :many
|
||||||
|
SELECT
|
||||||
|
*
|
||||||
|
FROM
|
||||||
|
agents;
|
||||||
|
|
||||||
|
-- name: CreateAgent :one
|
||||||
|
INSERT INTO
|
||||||
|
agents (
|
||||||
|
id,
|
||||||
|
hostname,
|
||||||
|
public_ip,
|
||||||
|
private_ips,
|
||||||
|
containers,
|
||||||
|
last_seen
|
||||||
|
)
|
||||||
|
VALUES
|
||||||
|
(?, ?, ?, ?, ?, ?) RETURNING *;
|
||||||
|
|
||||||
|
-- name: UpdateAgent :one
|
||||||
|
UPDATE agents
|
||||||
|
SET
|
||||||
|
hostname = ?,
|
||||||
|
public_ip = ?,
|
||||||
|
private_ips = ?,
|
||||||
|
containers = ?,
|
||||||
|
last_seen = ?
|
||||||
|
WHERE
|
||||||
|
id = ? RETURNING *;
|
||||||
|
|
||||||
|
-- name: UpsertAgent :one
|
||||||
|
INSERT INTO
|
||||||
|
agents (
|
||||||
|
id,
|
||||||
|
hostname,
|
||||||
|
public_ip,
|
||||||
|
private_ips,
|
||||||
|
containers,
|
||||||
|
last_seen
|
||||||
|
)
|
||||||
|
VALUES
|
||||||
|
(?, ?, ?, ?, ?, ?) ON CONFLICT (id) DO
|
||||||
|
UPDATE
|
||||||
|
SET
|
||||||
|
hostname = EXCLUDED.hostname,
|
||||||
|
public_ip = EXCLUDED.public_ip,
|
||||||
|
private_ips = EXCLUDED.private_ips,
|
||||||
|
containers = EXCLUDED.containers,
|
||||||
|
last_seen = EXCLUDED.last_seen RETURNING *;
|
||||||
|
|
||||||
|
-- name: DeleteAgentByID :exec
|
||||||
|
DELETE FROM agents
|
||||||
|
WHERE
|
||||||
|
id = ?;
|
||||||
|
|
||||||
|
-- name: DeleteAgentByHostname :exec
|
||||||
|
DELETE FROM agents
|
||||||
|
WHERE
|
||||||
|
hostname = ?;
|
||||||
|
|||||||
@@ -7,8 +7,53 @@ package db
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const createAgent = `-- name: CreateAgent :one
|
||||||
|
INSERT INTO
|
||||||
|
agents (
|
||||||
|
id,
|
||||||
|
hostname,
|
||||||
|
public_ip,
|
||||||
|
private_ips,
|
||||||
|
containers,
|
||||||
|
last_seen
|
||||||
|
)
|
||||||
|
VALUES
|
||||||
|
(?, ?, ?, ?, ?, ?) RETURNING id, hostname, public_ip, private_ips, containers, last_seen
|
||||||
|
`
|
||||||
|
|
||||||
|
type CreateAgentParams struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Hostname string `json:"hostname"`
|
||||||
|
PublicIp *string `json:"public_ip"`
|
||||||
|
PrivateIps interface{} `json:"private_ips"`
|
||||||
|
Containers interface{} `json:"containers"`
|
||||||
|
LastSeen *time.Time `json:"last_seen"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) CreateAgent(ctx context.Context, arg CreateAgentParams) (Agent, error) {
|
||||||
|
row := q.queryRow(ctx, q.createAgentStmt, createAgent,
|
||||||
|
arg.ID,
|
||||||
|
arg.Hostname,
|
||||||
|
arg.PublicIp,
|
||||||
|
arg.PrivateIps,
|
||||||
|
arg.Containers,
|
||||||
|
arg.LastSeen,
|
||||||
|
)
|
||||||
|
var i Agent
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.Hostname,
|
||||||
|
&i.PublicIp,
|
||||||
|
&i.PrivateIps,
|
||||||
|
&i.Containers,
|
||||||
|
&i.LastSeen,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
const createConfig = `-- name: CreateConfig :one
|
const createConfig = `-- name: CreateConfig :one
|
||||||
INSERT INTO
|
INSERT INTO
|
||||||
config (
|
config (
|
||||||
@@ -196,6 +241,28 @@ func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (User, e
|
|||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const deleteAgentByHostname = `-- name: DeleteAgentByHostname :exec
|
||||||
|
DELETE FROM agents
|
||||||
|
WHERE
|
||||||
|
hostname = ?
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) DeleteAgentByHostname(ctx context.Context, hostname string) error {
|
||||||
|
_, err := q.exec(ctx, q.deleteAgentByHostnameStmt, deleteAgentByHostname, hostname)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteAgentByID = `-- name: DeleteAgentByID :exec
|
||||||
|
DELETE FROM agents
|
||||||
|
WHERE
|
||||||
|
id = ?
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) DeleteAgentByID(ctx context.Context, id string) error {
|
||||||
|
_, err := q.exec(ctx, q.deleteAgentByIDStmt, deleteAgentByID, id)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
const deleteConfigByProfileID = `-- name: DeleteConfigByProfileID :exec
|
const deleteConfigByProfileID = `-- name: DeleteConfigByProfileID :exec
|
||||||
DELETE FROM config
|
DELETE FROM config
|
||||||
WHERE
|
WHERE
|
||||||
@@ -269,6 +336,17 @@ func (q *Queries) DeleteProviderByName(ctx context.Context, name string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const deleteSettingByID = `-- name: DeleteSettingByID :exec
|
||||||
|
DELETE FROM settings
|
||||||
|
WHERE
|
||||||
|
id = ?
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) DeleteSettingByID(ctx context.Context, id int64) error {
|
||||||
|
_, err := q.exec(ctx, q.deleteSettingByIDStmt, deleteSettingByID, id)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
const deleteSettingByKey = `-- name: DeleteSettingByKey :exec
|
const deleteSettingByKey = `-- name: DeleteSettingByKey :exec
|
||||||
DELETE FROM settings
|
DELETE FROM settings
|
||||||
WHERE
|
WHERE
|
||||||
@@ -302,6 +380,56 @@ func (q *Queries) DeleteUserByUsername(ctx context.Context, username string) err
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getAgentByHostname = `-- name: GetAgentByHostname :one
|
||||||
|
SELECT
|
||||||
|
id, hostname, public_ip, private_ips, containers, last_seen
|
||||||
|
FROM
|
||||||
|
agents
|
||||||
|
WHERE
|
||||||
|
hostname = ?
|
||||||
|
LIMIT
|
||||||
|
1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetAgentByHostname(ctx context.Context, hostname string) (Agent, error) {
|
||||||
|
row := q.queryRow(ctx, q.getAgentByHostnameStmt, getAgentByHostname, hostname)
|
||||||
|
var i Agent
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.Hostname,
|
||||||
|
&i.PublicIp,
|
||||||
|
&i.PrivateIps,
|
||||||
|
&i.Containers,
|
||||||
|
&i.LastSeen,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const getAgentByID = `-- name: GetAgentByID :one
|
||||||
|
SELECT
|
||||||
|
id, hostname, public_ip, private_ips, containers, last_seen
|
||||||
|
FROM
|
||||||
|
agents
|
||||||
|
WHERE
|
||||||
|
id = ?
|
||||||
|
LIMIT
|
||||||
|
1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetAgentByID(ctx context.Context, id string) (Agent, error) {
|
||||||
|
row := q.queryRow(ctx, q.getAgentByIDStmt, getAgentByID, id)
|
||||||
|
var i Agent
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.Hostname,
|
||||||
|
&i.PublicIp,
|
||||||
|
&i.PrivateIps,
|
||||||
|
&i.Containers,
|
||||||
|
&i.LastSeen,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
const getConfigByProfileID = `-- name: GetConfigByProfileID :one
|
const getConfigByProfileID = `-- name: GetConfigByProfileID :one
|
||||||
SELECT
|
SELECT
|
||||||
profile_id, overview, entrypoints, routers, services, middlewares, tls, version
|
profile_id, overview, entrypoints, routers, services, middlewares, tls, version
|
||||||
@@ -533,6 +661,43 @@ func (q *Queries) GetUserByUsername(ctx context.Context, username string) (User,
|
|||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const listAgents = `-- name: ListAgents :many
|
||||||
|
SELECT
|
||||||
|
id, hostname, public_ip, private_ips, containers, last_seen
|
||||||
|
FROM
|
||||||
|
agents
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) ListAgents(ctx context.Context) ([]Agent, error) {
|
||||||
|
rows, err := q.query(ctx, q.listAgentsStmt, listAgents)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []Agent
|
||||||
|
for rows.Next() {
|
||||||
|
var i Agent
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.Hostname,
|
||||||
|
&i.PublicIp,
|
||||||
|
&i.PrivateIps,
|
||||||
|
&i.Containers,
|
||||||
|
&i.LastSeen,
|
||||||
|
); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
items = append(items, i)
|
||||||
|
}
|
||||||
|
if err := rows.Close(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return items, nil
|
||||||
|
}
|
||||||
|
|
||||||
const listConfigs = `-- name: ListConfigs :many
|
const listConfigs = `-- name: ListConfigs :many
|
||||||
SELECT
|
SELECT
|
||||||
profile_id, overview, entrypoints, routers, services, middlewares, tls, version
|
profile_id, overview, entrypoints, routers, services, middlewares, tls, version
|
||||||
@@ -714,6 +879,48 @@ func (q *Queries) ListUsers(ctx context.Context) ([]User, error) {
|
|||||||
return items, nil
|
return items, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const updateAgent = `-- name: UpdateAgent :one
|
||||||
|
UPDATE agents
|
||||||
|
SET
|
||||||
|
hostname = ?,
|
||||||
|
public_ip = ?,
|
||||||
|
private_ips = ?,
|
||||||
|
containers = ?,
|
||||||
|
last_seen = ?
|
||||||
|
WHERE
|
||||||
|
id = ? RETURNING id, hostname, public_ip, private_ips, containers, last_seen
|
||||||
|
`
|
||||||
|
|
||||||
|
type UpdateAgentParams struct {
|
||||||
|
Hostname string `json:"hostname"`
|
||||||
|
PublicIp *string `json:"public_ip"`
|
||||||
|
PrivateIps interface{} `json:"private_ips"`
|
||||||
|
Containers interface{} `json:"containers"`
|
||||||
|
LastSeen *time.Time `json:"last_seen"`
|
||||||
|
ID string `json:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) UpdateAgent(ctx context.Context, arg UpdateAgentParams) (Agent, error) {
|
||||||
|
row := q.queryRow(ctx, q.updateAgentStmt, updateAgent,
|
||||||
|
arg.Hostname,
|
||||||
|
arg.PublicIp,
|
||||||
|
arg.PrivateIps,
|
||||||
|
arg.Containers,
|
||||||
|
arg.LastSeen,
|
||||||
|
arg.ID,
|
||||||
|
)
|
||||||
|
var i Agent
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.Hostname,
|
||||||
|
&i.PublicIp,
|
||||||
|
&i.PrivateIps,
|
||||||
|
&i.Containers,
|
||||||
|
&i.LastSeen,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
const updateConfig = `-- name: UpdateConfig :one
|
const updateConfig = `-- name: UpdateConfig :one
|
||||||
UPDATE config
|
UPDATE config
|
||||||
SET
|
SET
|
||||||
@@ -914,6 +1121,57 @@ func (q *Queries) UpdateUser(ctx context.Context, arg UpdateUserParams) (User, e
|
|||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const upsertAgent = `-- name: UpsertAgent :one
|
||||||
|
INSERT INTO
|
||||||
|
agents (
|
||||||
|
id,
|
||||||
|
hostname,
|
||||||
|
public_ip,
|
||||||
|
private_ips,
|
||||||
|
containers,
|
||||||
|
last_seen
|
||||||
|
)
|
||||||
|
VALUES
|
||||||
|
(?, ?, ?, ?, ?, ?) ON CONFLICT (id) DO
|
||||||
|
UPDATE
|
||||||
|
SET
|
||||||
|
hostname = EXCLUDED.hostname,
|
||||||
|
public_ip = EXCLUDED.public_ip,
|
||||||
|
private_ips = EXCLUDED.private_ips,
|
||||||
|
containers = EXCLUDED.containers,
|
||||||
|
last_seen = EXCLUDED.last_seen RETURNING id, hostname, public_ip, private_ips, containers, last_seen
|
||||||
|
`
|
||||||
|
|
||||||
|
type UpsertAgentParams struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Hostname string `json:"hostname"`
|
||||||
|
PublicIp *string `json:"public_ip"`
|
||||||
|
PrivateIps interface{} `json:"private_ips"`
|
||||||
|
Containers interface{} `json:"containers"`
|
||||||
|
LastSeen *time.Time `json:"last_seen"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) UpsertAgent(ctx context.Context, arg UpsertAgentParams) (Agent, error) {
|
||||||
|
row := q.queryRow(ctx, q.upsertAgentStmt, upsertAgent,
|
||||||
|
arg.ID,
|
||||||
|
arg.Hostname,
|
||||||
|
arg.PublicIp,
|
||||||
|
arg.PrivateIps,
|
||||||
|
arg.Containers,
|
||||||
|
arg.LastSeen,
|
||||||
|
)
|
||||||
|
var i Agent
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.Hostname,
|
||||||
|
&i.PublicIp,
|
||||||
|
&i.PrivateIps,
|
||||||
|
&i.Containers,
|
||||||
|
&i.LastSeen,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
const upsertProfile = `-- name: UpsertProfile :one
|
const upsertProfile = `-- name: UpsertProfile :one
|
||||||
INSERT INTO
|
INSERT INTO
|
||||||
profiles (id, name, url, username, password, tls)
|
profiles (id, name, url, username, password, tls)
|
||||||
|
|||||||
4
main.go
4
main.go
@@ -54,6 +54,10 @@ func main() {
|
|||||||
go traefik.Sync(ctx)
|
go traefik.Sync(ctx)
|
||||||
go dns.Sync(ctx)
|
go dns.Sync(ctx)
|
||||||
|
|
||||||
|
// Start the grpc server
|
||||||
|
go api.Server(flags.Agent.Port)
|
||||||
|
|
||||||
|
// Start the WebUI server
|
||||||
srv := &http.Server{
|
srv := &http.Server{
|
||||||
Addr: ":" + flags.Port,
|
Addr: ":" + flags.Port,
|
||||||
Handler: api.Routes(flags.UseAuth),
|
Handler: api.Routes(flags.UseAuth),
|
||||||
|
|||||||
@@ -7,7 +7,10 @@ import (
|
|||||||
"log/slog"
|
"log/slog"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/exp/slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Public IP APIs
|
// Public IP APIs
|
||||||
@@ -69,3 +72,40 @@ func GetPublicIP() (string, error) {
|
|||||||
}
|
}
|
||||||
return "", fmt.Errorf("failed to get public IP")
|
return "", fmt.Errorf("failed to get public IP")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetPrivateIP() ([]string, error) {
|
||||||
|
var ips []string
|
||||||
|
|
||||||
|
interfaces, err := net.Interfaces()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
excluded := []string{"lo", "docker", "br-", "veth", "kube", "cni"}
|
||||||
|
for _, iface := range interfaces {
|
||||||
|
if slices.ContainsFunc(excluded, func(s string) bool {
|
||||||
|
return strings.Contains(iface.Name, s)
|
||||||
|
}) || iface.Flags&net.FlagUp == 0 {
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
addrs, err := iface.Addrs()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, addr := range addrs {
|
||||||
|
if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
|
||||||
|
if ipnet.IP.To4() != nil {
|
||||||
|
ips = append(ips, ipnet.IP.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(ips) == 0 {
|
||||||
|
return nil, errors.New("no private IP addresses found")
|
||||||
|
}
|
||||||
|
|
||||||
|
return ips, nil
|
||||||
|
}
|
||||||
@@ -4,16 +4,26 @@ package util
|
|||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang-jwt/jwt/v5"
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Claims struct {
|
||||||
|
Username string `json:"username,omitempty"`
|
||||||
|
ServerURL string `json:"server_url,omitempty"`
|
||||||
|
Secret string `json:"secret,omitempty"`
|
||||||
|
jwt.RegisteredClaims
|
||||||
|
}
|
||||||
|
|
||||||
// GenPassword generates a random password of the specified length
|
// GenPassword generates a random password of the specified length
|
||||||
func GenPassword(length int) string {
|
func GenPassword(length int) string {
|
||||||
bytes := make([]byte, length)
|
bytes := make([]byte, length)
|
||||||
@@ -53,6 +63,73 @@ func HashBasicAuth(userString string) (string, error) {
|
|||||||
return user + ":" + string(hash), nil
|
return user + ":" + string(hash), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EncodeUserJWT generates a JWT for user login
|
||||||
|
func EncodeUserJWT(username string) (string, error) {
|
||||||
|
secret := os.Getenv("SECRET")
|
||||||
|
if secret == "" {
|
||||||
|
return "", errors.New("SECRET environment variable is not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
if username == "" {
|
||||||
|
return "", errors.New("username cannot be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
expirationTime := time.Now().Add(24 * time.Hour)
|
||||||
|
claims := &Claims{
|
||||||
|
Username: username,
|
||||||
|
RegisteredClaims: jwt.RegisteredClaims{
|
||||||
|
ExpiresAt: jwt.NewNumericDate(expirationTime),
|
||||||
|
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||||
|
return token.SignedString([]byte(secret))
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeAgentJWT generates a JWT for the agent
|
||||||
|
func EncodeAgentJWT(serverURL string) (string, error) {
|
||||||
|
secret := os.Getenv("SECRET")
|
||||||
|
if secret == "" {
|
||||||
|
return "", errors.New("SECRET environment variable is not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
if serverURL == "" {
|
||||||
|
return "", errors.New("serverURL cannot be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
expirationTime := time.Now().Add(14 * 24 * time.Hour) // 14 days
|
||||||
|
claims := Claims{
|
||||||
|
ServerURL: serverURL,
|
||||||
|
Secret: secret, // Optionally store the secret here
|
||||||
|
RegisteredClaims: jwt.RegisteredClaims{
|
||||||
|
ExpiresAt: jwt.NewNumericDate(expirationTime),
|
||||||
|
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||||
|
return token.SignedString([]byte(secret)) // Server uses its secret for signing
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeJWT decodes the token and returns claims if valid
|
||||||
|
func DecodeJWT(tokenString string) (*Claims, error) {
|
||||||
|
claims := &Claims{}
|
||||||
|
token, err := jwt.ParseWithClaims(
|
||||||
|
tokenString,
|
||||||
|
claims,
|
||||||
|
func(token *jwt.Token) (interface{}, error) {
|
||||||
|
// Validate the algorithm and return the server's secret
|
||||||
|
return []byte(os.Getenv("SECRET")), nil // Use the secret from claims to verify
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
if err != nil || !token.Valid {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return claims, nil
|
||||||
|
}
|
||||||
|
|
||||||
// IsValidURL checks if a URL is valid url string
|
// IsValidURL checks if a URL is valid url string
|
||||||
func IsValidURL(u string) bool {
|
func IsValidURL(u string) bool {
|
||||||
// If no scheme is provided, prepend "http://"
|
// If no scheme is provided, prepend "http://"
|
||||||
|
|||||||
Reference in New Issue
Block a user