Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ per-cloud glue. The API follows a Karpenter-style split:
<img src="site/images/arch.png" alt="Nebula architecture: the operator's webhook, virtual kubelet and placement controller drive NodePools and NodeClaims onto hyperscalers, NeoClouds, Kubernetes clusters and on-prem servers" width="90%">
</p>

## Features

- **Kubernetes-native experience.** Existing Deployments and Jobs opt in via labels; no new workload type and no per-cloud glue.
- **Multi-provider support.** Modal and AWS today, with more to come.
- **Policy-driven placement.** Flexible NodePool spec to pick providers by cost, availability, and region, with failover and network egress policy.
- **Cost tracking.** Out-of-the-box per-instance cost tracking.
- **Observability.** Rich metrics and logs for placement, provisioning, and instance lifecycle.

## How it works

1. **Opt in.** You label a Pod to request an accelerator.
Expand Down Expand Up @@ -64,6 +72,11 @@ spec:
strategy: Ordered # try providers in listed order (or LowestPrice)
failover:
blocklistTTL: 10m # how long a failed placement is skipped
egress: # outbound policy; omitted = Open
mode: Allowlist # or Blocked to permit nothing
targets: # CIDRs, bare IPs and domains, wildcards allowed
- 10.0.0.0/8
- "*.huggingface.co"
```

## Opting a workload in
Expand Down
4 changes: 2 additions & 2 deletions pkg/provider/catalog/catalog.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,8 @@ func parseCSV(r io.Reader) ([]provider.Offering, error) {
// ParseFloat takes "NaN" and "Inf" as valid floats. Refused at the boundary because a rate
// is pinned onto the claim and integrated from there — the damage is downstream, in a
// durable ledger and a counter that cannot be corrected, not in this row.
if math.IsNaN(price) || math.IsInf(price, 0) {
return nil, fmt.Errorf("row %d: price_per_hour %q is not a finite number", i, field(rec, colPrice))
if math.IsNaN(price) || math.IsInf(price, 0) || price < 0 {
return nil, fmt.Errorf("row %d: price_per_hour %q must be a non-negative finite number", i, field(rec, colPrice))
Comment thread
kerthcet marked this conversation as resolved.
Comment thread
kerthcet marked this conversation as resolved.
}
available, err := strconv.ParseBool(field(rec, colAvailable))
if err != nil {
Expand Down
Loading