mirror of
https://github.com/fosrl/newt.git
synced 2026-04-05 01:16:37 +00:00
Compare commits
27 Commits
logging-pr
...
1.11.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cd4782265a | ||
|
|
2e02c9b7a9 | ||
|
|
5c329be1f3 | ||
|
|
732e788c66 | ||
|
|
aa42b3623d | ||
|
|
4f42560e26 | ||
|
|
c2187de482 | ||
|
|
5ced7d6909 | ||
|
|
4e6e79ad21 | ||
|
|
abe6e2e400 | ||
|
|
f432a17c16 | ||
|
|
6f96169ff1 | ||
|
|
575942c4be | ||
|
|
16864fc1d7 | ||
|
|
f925c681d2 | ||
|
|
e01b0ae9c7 | ||
|
|
f4d071fe27 | ||
|
|
8d82460a76 | ||
|
|
5208117c56 | ||
|
|
212bdf765a | ||
|
|
b045a0f5d4 | ||
|
|
d7741df514 | ||
|
|
8e188933a2 | ||
|
|
a13c7c6e65 | ||
|
|
bc44ca1aba | ||
|
|
a76089db98 | ||
|
|
627ec2fdbc |
40
.github/workflows/cicd.yml
vendored
40
.github/workflows/cicd.yml
vendored
@@ -235,17 +235,17 @@ jobs:
|
||||
# uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
|
||||
|
||||
#- name: Set up Docker Buildx
|
||||
# uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
|
||||
# uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
|
||||
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
|
||||
with:
|
||||
registry: docker.io
|
||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
||||
|
||||
- name: Log in to GHCR
|
||||
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
|
||||
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
@@ -259,12 +259,12 @@ jobs:
|
||||
echo "DOCKERHUB_IMAGE=${DOCKERHUB_IMAGE,,}" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
|
||||
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
|
||||
|
||||
# Build ONLY amd64 and push arch-specific tag suffixes used later for manifest creation.
|
||||
- name: Build and push (amd64 -> *:amd64-TAG)
|
||||
id: build_amd
|
||||
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2
|
||||
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
@@ -363,14 +363,14 @@ jobs:
|
||||
echo "Checked out $(git rev-parse --short HEAD) for tag ${TAG}"
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
|
||||
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
|
||||
with:
|
||||
registry: docker.io
|
||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
||||
|
||||
- name: Log in to GHCR
|
||||
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
|
||||
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
@@ -384,12 +384,12 @@ jobs:
|
||||
echo "DOCKERHUB_IMAGE=${DOCKERHUB_IMAGE,,}" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
|
||||
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
|
||||
|
||||
# Build ONLY arm64 and push arch-specific tag suffixes used later for manifest creation.
|
||||
- name: Build and push (arm64 -> *:arm64-TAG)
|
||||
id: build_arm
|
||||
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2
|
||||
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
@@ -478,14 +478,14 @@ jobs:
|
||||
echo "Checked out $(git rev-parse --short HEAD) for tag ${TAG}"
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
|
||||
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
|
||||
with:
|
||||
registry: docker.io
|
||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
||||
|
||||
- name: Log in to GHCR
|
||||
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
|
||||
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
@@ -502,11 +502,11 @@ jobs:
|
||||
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
|
||||
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
|
||||
|
||||
- name: Build and push (arm/v7 -> *:armv7-TAG)
|
||||
id: build_armv7
|
||||
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2
|
||||
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # v7.0.0
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
@@ -551,14 +551,14 @@ jobs:
|
||||
#PUBLISH_MINOR: ${{ github.event_name == 'workflow_dispatch' && inputs.publish_minor || vars.PUBLISH_MINOR }}
|
||||
steps:
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
|
||||
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
|
||||
with:
|
||||
registry: docker.io
|
||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
||||
|
||||
- name: Log in to GHCR
|
||||
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
|
||||
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
@@ -572,7 +572,7 @@ jobs:
|
||||
echo "DOCKERHUB_IMAGE=${DOCKERHUB_IMAGE,,}" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Set up Docker Buildx (needed for imagetools)
|
||||
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
|
||||
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
|
||||
|
||||
- name: Create & push multi-arch index (GHCR :TAG) via imagetools
|
||||
shell: bash
|
||||
@@ -656,14 +656,14 @@ jobs:
|
||||
go-version-file: go.mod
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
|
||||
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
|
||||
with:
|
||||
registry: docker.io
|
||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
||||
|
||||
- name: Log in to GHCR
|
||||
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
|
||||
uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
@@ -687,7 +687,7 @@ jobs:
|
||||
sudo apt-get install -y jq
|
||||
|
||||
- name: Set up Docker Buildx (needed for imagetools)
|
||||
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
|
||||
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
|
||||
|
||||
- name: Resolve multi-arch digest refs (by TAG)
|
||||
shell: bash
|
||||
@@ -759,7 +759,7 @@ jobs:
|
||||
cosign public-key --key env://COSIGN_PRIVATE_KEY >/dev/null
|
||||
|
||||
- name: Generate SBOM (SPDX JSON) from GHCR digest
|
||||
uses: aquasecurity/trivy-action@97e0b3872f55f89b95b2f65b3dbab56962816478 # v0.34.2
|
||||
uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # v0.35.0
|
||||
with:
|
||||
image-ref: ${{ env.GHCR_REF }}
|
||||
format: spdx-json
|
||||
|
||||
2
.github/workflows/stale-bot.yml
vendored
2
.github/workflows/stale-bot.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@997185467fa4f803885201cee163a9f38240193d # v10.1.1
|
||||
- uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f # v10.2.0
|
||||
with:
|
||||
days-before-stale: 14
|
||||
days-before-close: 14
|
||||
|
||||
@@ -540,12 +540,12 @@ func interpolateBlueprint(data []byte) []byte {
|
||||
})
|
||||
}
|
||||
|
||||
func sendBlueprint(client *websocket.Client) error {
|
||||
if blueprintFile == "" {
|
||||
func sendBlueprint(client *websocket.Client, file string) error {
|
||||
if file == "" {
|
||||
return nil
|
||||
}
|
||||
// try to read the blueprint file
|
||||
blueprintData, err := os.ReadFile(blueprintFile)
|
||||
blueprintData, err := os.ReadFile(file)
|
||||
if err != nil {
|
||||
logger.Error("Failed to read blueprint file: %v", err)
|
||||
} else {
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"endpoint": "http://you.fosrl.io",
|
||||
"provisioningKey": "spk-xt1opb0fkoqb7qb.hi44jciamqcrdaja4lvz3kp52pl3lssamp6asuyx"
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"endpoint": "http://you.fosrl.io",
|
||||
"provisioningKey": "spk-xt1opb0fkoqb7qb.hi44jciamqcrdaja4lvz3kp52pl3lssamp6asuyx"
|
||||
}
|
||||
@@ -35,7 +35,7 @@
|
||||
inherit version;
|
||||
src = pkgs.nix-gitignore.gitignoreSource [ ] ./.;
|
||||
|
||||
vendorHash = "sha256-kmQM8Yy5TuOiNpMpUme/2gfE+vrhUK+0AphN+p71wGs=";
|
||||
vendorHash = "sha256-YIcuj1S+ZWAzXZOMZbppTvsDcW1W1Sy8ynfMkzLMQpM=";
|
||||
|
||||
nativeInstallCheckInputs = [ pkgs.versionCheckHook ];
|
||||
|
||||
|
||||
4
go.mod
4
go.mod
@@ -4,7 +4,7 @@ go 1.25.0
|
||||
|
||||
require (
|
||||
github.com/docker/docker v28.5.2+incompatible
|
||||
github.com/gaissmai/bart v0.26.0
|
||||
github.com/gaissmai/bart v0.26.1
|
||||
github.com/gorilla/websocket v1.5.3
|
||||
github.com/prometheus/client_golang v1.23.2
|
||||
github.com/vishvananda/netlink v1.3.1
|
||||
@@ -24,7 +24,7 @@ require (
|
||||
golang.zx2c4.com/wireguard v0.0.0-20250521234502-f333402bd9cb
|
||||
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20241231184526-a9ab2273dd10
|
||||
golang.zx2c4.com/wireguard/windows v0.5.3
|
||||
google.golang.org/grpc v1.79.1
|
||||
google.golang.org/grpc v1.79.3
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
gvisor.dev/gvisor v0.0.0-20250503011706-39ed1f5ac29c
|
||||
software.sslmate.com/src/go-pkcs12 v0.7.0
|
||||
|
||||
8
go.sum
8
go.sum
@@ -26,8 +26,8 @@ github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw
|
||||
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/gaissmai/bart v0.26.0 h1:xOZ57E9hJLBiQaSyeZa9wgWhGuzfGACgqp4BE77OkO0=
|
||||
github.com/gaissmai/bart v0.26.0/go.mod h1:GREWQfTLRWz/c5FTOsIw+KkscuFkIV5t8Rp7Nd1Td5c=
|
||||
github.com/gaissmai/bart v0.26.1 h1:+w4rnLGNlA2GDVn382Tfe3jOsK5vOr5n4KmigJ9lbTo=
|
||||
github.com/gaissmai/bart v0.26.1/go.mod h1:GREWQfTLRWz/c5FTOsIw+KkscuFkIV5t8Rp7Nd1Td5c=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
@@ -159,8 +159,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57 h1:
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:kSJwQxqmFXeo79zOmbrALdflXQeAYcUbgS7PbpMknCY=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57 h1:mWPCjDEyshlQYzBpMNHaEof6UX1PmHcaUODUywQ0uac=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260209200024-4cfbd4190f57/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
|
||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE=
|
||||
google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
49
main.go
49
main.go
@@ -155,8 +155,9 @@ var (
|
||||
region string
|
||||
metricsAsyncBytes bool
|
||||
pprofEnabled bool
|
||||
blueprintFile string
|
||||
noCloud bool
|
||||
blueprintFile string
|
||||
provisioningBlueprintFile string
|
||||
noCloud bool
|
||||
|
||||
// New mTLS configuration variables
|
||||
tlsClientCert string
|
||||
@@ -169,6 +170,9 @@ var (
|
||||
// Provisioning key – exchanged once for a permanent newt ID + secret
|
||||
provisioningKey string
|
||||
|
||||
// Optional name for the site created during provisioning
|
||||
newtName string
|
||||
|
||||
// Path to config file (overrides CONFIG_FILE env var and default location)
|
||||
configFile string
|
||||
)
|
||||
@@ -281,9 +285,11 @@ func runNewtMain(ctx context.Context) {
|
||||
tlsPrivateKey = os.Getenv("TLS_CLIENT_CERT")
|
||||
}
|
||||
blueprintFile = os.Getenv("BLUEPRINT_FILE")
|
||||
provisioningBlueprintFile = os.Getenv("PROVISIONING_BLUEPRINT_FILE")
|
||||
noCloudEnv := os.Getenv("NO_CLOUD")
|
||||
noCloud = noCloudEnv == "true"
|
||||
provisioningKey = os.Getenv("NEWT_PROVISIONING_KEY")
|
||||
newtName = os.Getenv("NEWT_NAME")
|
||||
configFile = os.Getenv("CONFIG_FILE")
|
||||
|
||||
if endpoint == "" {
|
||||
@@ -336,6 +342,9 @@ func runNewtMain(ctx context.Context) {
|
||||
if provisioningKey == "" {
|
||||
flag.StringVar(&provisioningKey, "provisioning-key", "", "One-time provisioning key used to obtain a newt ID and secret from the server")
|
||||
}
|
||||
if newtName == "" {
|
||||
flag.StringVar(&newtName, "name", "", "Name for the site created during provisioning (supports {{env.VAR}} interpolation)")
|
||||
}
|
||||
if configFile == "" {
|
||||
flag.StringVar(&configFile, "config-file", "", "Path to config file (overrides CONFIG_FILE env var and default location)")
|
||||
}
|
||||
@@ -386,6 +395,9 @@ func runNewtMain(ctx context.Context) {
|
||||
if blueprintFile == "" {
|
||||
flag.StringVar(&blueprintFile, "blueprint-file", "", "Path to blueprint file (if unset, no blueprint will be applied)")
|
||||
}
|
||||
if provisioningBlueprintFile == "" {
|
||||
flag.StringVar(&provisioningBlueprintFile, "provisioning-blueprint-file", "", "Path to blueprint file applied once after a provisioning credential exchange (if unset, no provisioning blueprint will be applied)")
|
||||
}
|
||||
if noCloudEnv == "" {
|
||||
flag.BoolVar(&noCloud, "no-cloud", false, "Disable cloud failover")
|
||||
}
|
||||
@@ -623,6 +635,9 @@ func runNewtMain(ctx context.Context) {
|
||||
if provisioningKey != "" && client.GetConfig().ProvisioningKey == "" {
|
||||
client.GetConfig().ProvisioningKey = provisioningKey
|
||||
}
|
||||
if newtName != "" && client.GetConfig().Name == "" {
|
||||
client.GetConfig().Name = newtName
|
||||
}
|
||||
|
||||
endpoint = client.GetConfig().Endpoint // Update endpoint from config
|
||||
id = client.GetConfig().ID // Update ID from config
|
||||
@@ -1810,6 +1825,34 @@ persistent_keepalive_interval=5`, util.FixKey(privateKey.String()), util.FixKey(
|
||||
} else {
|
||||
logger.Warn("CLIENTS WILL NOT WORK ON THIS VERSION OF NEWT WITH THIS VERSION OF PANGOLIN, PLEASE UPDATE THE SERVER TO 1.13 OR HIGHER OR DOWNGRADE NEWT")
|
||||
}
|
||||
|
||||
sendBlueprint(client, blueprintFile)
|
||||
if client.WasJustProvisioned() {
|
||||
logger.Info("Provisioning detected – sending provisioning blueprint")
|
||||
sendBlueprint(client, provisioningBlueprintFile)
|
||||
}
|
||||
} else {
|
||||
// Resend current health check status for all targets in case the server
|
||||
// missed updates while newt was disconnected.
|
||||
targets := healthMonitor.GetTargets()
|
||||
if len(targets) > 0 {
|
||||
healthStatuses := make(map[int]interface{})
|
||||
for id, target := range targets {
|
||||
healthStatuses[id] = map[string]interface{}{
|
||||
"status": target.Status.String(),
|
||||
"lastCheck": target.LastCheck.Format(time.RFC3339),
|
||||
"checkCount": target.CheckCount,
|
||||
"lastError": target.LastError,
|
||||
"config": target.Config,
|
||||
}
|
||||
}
|
||||
logger.Debug("Reconnected: resending health check status for %d targets", len(healthStatuses))
|
||||
if err := client.SendMessage("newt/healthcheck/status", map[string]interface{}{
|
||||
"targets": healthStatuses,
|
||||
}); err != nil {
|
||||
logger.Error("Failed to resend health check status on reconnect: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Send registration message to the server for backward compatibility
|
||||
@@ -1822,8 +1865,6 @@ persistent_keepalive_interval=5`, util.FixKey(privateKey.String()), util.FixKey(
|
||||
"chainId": bcChainId,
|
||||
})
|
||||
|
||||
sendBlueprint(client)
|
||||
|
||||
if err != nil {
|
||||
logger.Error("Failed to send registration message: %v", err)
|
||||
return err
|
||||
|
||||
@@ -53,6 +53,7 @@ type Client struct {
|
||||
processingMessage bool // Flag to track if a message is currently being processed
|
||||
processingMux sync.RWMutex // Protects processingMessage
|
||||
processingWg sync.WaitGroup // WaitGroup to wait for message processing to complete
|
||||
justProvisioned bool // Set to true when provisionIfNeeded exchanges a key for permanent credentials
|
||||
}
|
||||
|
||||
type ClientOption func(*Client)
|
||||
@@ -102,6 +103,16 @@ func (c *Client) OnTokenUpdate(callback func(token string)) {
|
||||
c.onTokenUpdate = callback
|
||||
}
|
||||
|
||||
// WasJustProvisioned reports whether the client exchanged a provisioning key
|
||||
// for permanent credentials during the most recent connection attempt. It
|
||||
// consumes the flag – subsequent calls return false until provisioning occurs
|
||||
// again (which, in practice, never happens once credentials are persisted).
|
||||
func (c *Client) WasJustProvisioned() bool {
|
||||
v := c.justProvisioned
|
||||
c.justProvisioned = false
|
||||
return v
|
||||
}
|
||||
|
||||
func (c *Client) metricsContext() context.Context {
|
||||
c.metricsCtxMu.RLock()
|
||||
defer c.metricsCtxMu.RUnlock()
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -99,6 +100,10 @@ func (c *Client) loadConfig() error {
|
||||
if c.config.ProvisioningKey == "" {
|
||||
c.config.ProvisioningKey = config.ProvisioningKey
|
||||
}
|
||||
// Always load the name from the file if not already set
|
||||
if c.config.Name == "" {
|
||||
c.config.Name = config.Name
|
||||
}
|
||||
|
||||
// Check if CLI args provided values that override file values
|
||||
if (!fileHadID && originalConfig.ID != "") ||
|
||||
@@ -135,6 +140,21 @@ func (c *Client) saveConfig() error {
|
||||
return err
|
||||
}
|
||||
|
||||
// interpolateString replaces {{env.VAR}} tokens in s with the corresponding
|
||||
// environment variable values. Tokens that do not match a supported scheme are
|
||||
// left unchanged, mirroring the blueprint interpolation logic.
|
||||
func interpolateString(s string) string {
|
||||
re := regexp.MustCompile(`\{\{([^}]+)\}\}`)
|
||||
return re.ReplaceAllStringFunc(s, func(match string) string {
|
||||
inner := strings.TrimSpace(match[2 : len(match)-2])
|
||||
if strings.HasPrefix(inner, "env.") {
|
||||
varName := strings.TrimPrefix(inner, "env.")
|
||||
return os.Getenv(varName)
|
||||
}
|
||||
return match
|
||||
})
|
||||
}
|
||||
|
||||
// provisionIfNeeded checks whether a provisioning key is present and, if so,
|
||||
// exchanges it for a newt ID and secret by calling the registration endpoint.
|
||||
// On success the config is updated in-place and flagged for saving so that
|
||||
@@ -158,9 +178,15 @@ func (c *Client) provisionIfNeeded() error {
|
||||
}
|
||||
baseEndpoint := strings.TrimRight(baseURL.String(), "/")
|
||||
|
||||
// Interpolate any {{env.VAR}} tokens in the name before sending.
|
||||
name := interpolateString(c.config.Name)
|
||||
|
||||
reqBody := map[string]interface{}{
|
||||
"provisioningKey": c.config.ProvisioningKey,
|
||||
}
|
||||
if name != "" {
|
||||
reqBody["name"] = name
|
||||
}
|
||||
jsonData, err := json.Marshal(reqBody)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal provisioning request: %w", err)
|
||||
@@ -236,7 +262,9 @@ func (c *Client) provisionIfNeeded() error {
|
||||
c.config.ID = provResp.Data.NewtID
|
||||
c.config.Secret = provResp.Data.Secret
|
||||
c.config.ProvisioningKey = ""
|
||||
c.config.Name = ""
|
||||
c.configNeedsSave = true
|
||||
c.justProvisioned = true
|
||||
|
||||
// Save immediately so that if the subsequent connection attempt fails the
|
||||
// provisioning key is already gone from disk and the next retry uses the
|
||||
|
||||
@@ -6,6 +6,7 @@ type Config struct {
|
||||
Endpoint string `json:"endpoint"`
|
||||
TlsClientCert string `json:"tlsClientCert"`
|
||||
ProvisioningKey string `json:"provisioningKey,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
}
|
||||
|
||||
type TokenResponse struct {
|
||||
|
||||
Reference in New Issue
Block a user