mirror of
https://github.com/hanzoai/compute.git
synced 2026-10-30 14:50:41 +00:00
visor manages VMs across DO/Hetzner/Lightsail/Azure/GCP/Proxmox. It is deliberately the non-cluster path, and it linked client-go twice. autoscaler/ is deleted. It listed Pending pods via rest.InClusterConfig and scaled DOKS node pools — a cluster autoscaler living inside the VM manager. It was gated on autoscalerClusters, which is set in no deployment, so it had never run. service/doks.go is untouched: pure godo, still serving node-pool CRUD. object/coordinator.go now elects over ha.Membership — the interface hanzoai/ha already defines, reused rather than re-declared. With nothing registered the default reports an ERROR, not an empty set: an empty set is the positive claim "I have no peers", which is exactly the lie that double-debits a two-replica Deployment. Only an error carries "I don't know who my peers are". That default means no source, no metering, so a source had to be chosen. It is ha.Static in main.go's serve(), paired with replicas: 1 in universe. The sole process is the sole writer, so exactly-once holds by construction. It is registered in serve() and NOT in visor.Bootstrap(), which is shared verbatim with the embedded cloud mount whose replica count is cloud's, not ours. The two halves are one change: ha.Static at replicas: 2 bills every customer twice an hour. Both sides now carry a comment pointing at the other. Also corrects the comment that made this invisible. Shared() said "Postgres under both backends"; under Base it is the pod-local _global SQLite coord, so the lease PK does not span pods and the election is the only thing holding the line — not belt-and-braces over a global constraint, as the doc implied. k8s/rbac.yaml is a bare ServiceAccount: visor holds zero cluster permissions. go.mod loses every k8s.io/* and sigs.k8s.io/* entry, not just client-go. Co-authored-by: Hanzo Dev <[email protected]>
61 lines
2.4 KiB
Go
61 lines
2.4 KiB
Go
// Copyright 2026 Hanzo Industries Inc. All Rights Reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package routers
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/zap-proto/zip"
|
|
"github.com/zap-proto/zip/middleware"
|
|
)
|
|
|
|
// TestPreflightAllowsBearerToken drives the exact request a browser sends before
|
|
// it will call visor with a token, and asserts the answer permits it.
|
|
//
|
|
// This is a real preflight rather than an assertion over corsPolicy's fields,
|
|
// because the field being set is not the fact that matters — what matters is
|
|
// what the middleware writes into Access-Control-Allow-Headers. Tabs calls
|
|
// /v1/machines from tabs.hanzo.ai with an IAM bearer token; with Authorization
|
|
// missing from the answer, Chrome never sends the request and the whole feature
|
|
// is inert with no server-side trace of it having been tried.
|
|
func TestPreflightAllowsBearerToken(t *testing.T) {
|
|
app := zip.New(zip.Config{})
|
|
app.Use(middleware.CORS(corsPolicy))
|
|
registerAPI(app)
|
|
|
|
req := httptest.NewRequest(http.MethodOptions, "/v1/machines?kind=tab", nil)
|
|
req.Header.Set("Origin", "https://tabs.hanzo.ai")
|
|
req.Header.Set("Access-Control-Request-Method", http.MethodGet)
|
|
req.Header.Set("Access-Control-Request-Headers", "authorization")
|
|
|
|
res, err := app.Fiber().Test(req)
|
|
if err != nil {
|
|
t.Fatalf("preflight: %v", err)
|
|
}
|
|
if res.StatusCode != http.StatusNoContent && res.StatusCode != http.StatusOK {
|
|
t.Fatalf("preflight status = %d, want 204 or 200", res.StatusCode)
|
|
}
|
|
allowed := res.Header.Get("Access-Control-Allow-Headers")
|
|
if !strings.Contains(strings.ToLower(allowed), "authorization") {
|
|
t.Fatalf("Access-Control-Allow-Headers = %q, want it to permit Authorization", allowed)
|
|
}
|
|
if origin := res.Header.Get("Access-Control-Allow-Origin"); origin == "" {
|
|
t.Fatal("Access-Control-Allow-Origin is empty, so no browser may read the response")
|
|
}
|
|
}
|