Skip to content
Merged
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.7.0"
".": "0.8.0"
}
8 changes: 4 additions & 4 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_endpoints: 24
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fhypeman-8fded10e90df28c07b64a92d12d665d54749b9fc13c35520667637fc596957d9.yml
openapi_spec_hash: 7374a732372bddf7f2c0b532b56ae3fb
config_hash: 510018ffa6ad6a17875954f66fe69598
configured_endpoints: 30
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fhypeman-28e78b73c796f9ee866671ed946402b5d569e683c3207d57c9143eb7d6f83fb6.yml
openapi_spec_hash: fce0ac8713369a5f048bac684ed34fc8
config_hash: f65a6a2bcef49a9f623212f9de6d6f6f
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
# Changelog

## 0.8.0 (2025-12-23)

Full Changelog: [v0.7.0...v0.8.0](https://github.com/onkernel/hypeman-go/compare/v0.7.0...v0.8.0)

### Features

* add hypeman cp for file copy to/from running VMs ([49ea898](https://github.com/onkernel/hypeman-go/commit/49ea89852eed5e0893febc4c68d295a0d1a8bfe5))
* **encoder:** support bracket encoding form-data object members ([8ab31e8](https://github.com/onkernel/hypeman-go/commit/8ab31e89c70baa967842c1c160d0b49db44b089a))
* gpu passthrough ([067a01b](https://github.com/onkernel/hypeman-go/commit/067a01b4ac06e82c2db6b165127144afa18a691d))


### Bug Fixes

* skip usage tests that don't work with Prism ([d62b246](https://github.com/onkernel/hypeman-go/commit/d62b2466715247e7d083ab7ef33040e5da036bd8))


### Chores

* add float64 to valid types for RegisterFieldValidator ([b4666fd](https://github.com/onkernel/hypeman-go/commit/b4666fd1bfcdd17b0a4d4bf88541670cd40c8b1c))

## 0.7.0 (2025-12-11)

Full Changelog: [v0.6.0...v0.7.0](https://github.com/onkernel/hypeman-go/compare/v0.6.0...v0.7.0)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Or to pin the version:
<!-- x-release-please-start-version -->

```sh
go get -u 'github.com/onkernel/hypeman-go@v0.7.0'
go get -u 'github.com/onkernel/hypeman-go@v0.8.0'
```

<!-- x-release-please-end -->
Expand Down
18 changes: 18 additions & 0 deletions api.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ Params Types:
Response Types:

- <a href="https://pkg.go.dev/github.com/onkernel/hypeman-go">hypeman</a>.<a href="https://pkg.go.dev/github.com/onkernel/hypeman-go#Instance">Instance</a>
- <a href="https://pkg.go.dev/github.com/onkernel/hypeman-go">hypeman</a>.<a href="https://pkg.go.dev/github.com/onkernel/hypeman-go#PathInfo">PathInfo</a>
- <a href="https://pkg.go.dev/github.com/onkernel/hypeman-go">hypeman</a>.<a href="https://pkg.go.dev/github.com/onkernel/hypeman-go#VolumeMount">VolumeMount</a>

Methods:
Expand All @@ -42,6 +43,7 @@ Methods:
- <code title="post /instances/{id}/restore">client.Instances.<a href="https://pkg.go.dev/github.com/onkernel/hypeman-go#InstanceService.Restore">Restore</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>) (<a href="https://pkg.go.dev/github.com/onkernel/hypeman-go">hypeman</a>.<a href="https://pkg.go.dev/github.com/onkernel/hypeman-go#Instance">Instance</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
- <code title="post /instances/{id}/standby">client.Instances.<a href="https://pkg.go.dev/github.com/onkernel/hypeman-go#InstanceService.Standby">Standby</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>) (<a href="https://pkg.go.dev/github.com/onkernel/hypeman-go">hypeman</a>.<a href="https://pkg.go.dev/github.com/onkernel/hypeman-go#Instance">Instance</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
- <code title="post /instances/{id}/start">client.Instances.<a href="https://pkg.go.dev/github.com/onkernel/hypeman-go#InstanceService.Start">Start</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>) (<a href="https://pkg.go.dev/github.com/onkernel/hypeman-go">hypeman</a>.<a href="https://pkg.go.dev/github.com/onkernel/hypeman-go#Instance">Instance</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
- <code title="get /instances/{id}/stat">client.Instances.<a href="https://pkg.go.dev/github.com/onkernel/hypeman-go#InstanceService.Stat">Stat</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, query <a href="https://pkg.go.dev/github.com/onkernel/hypeman-go">hypeman</a>.<a href="https://pkg.go.dev/github.com/onkernel/hypeman-go#InstanceStatParams">InstanceStatParams</a>) (<a href="https://pkg.go.dev/github.com/onkernel/hypeman-go">hypeman</a>.<a href="https://pkg.go.dev/github.com/onkernel/hypeman-go#PathInfo">PathInfo</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
- <code title="post /instances/{id}/stop">client.Instances.<a href="https://pkg.go.dev/github.com/onkernel/hypeman-go#InstanceService.Stop">Stop</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>) (<a href="https://pkg.go.dev/github.com/onkernel/hypeman-go">hypeman</a>.<a href="https://pkg.go.dev/github.com/onkernel/hypeman-go#Instance">Instance</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>

## Volumes
Expand All @@ -65,6 +67,22 @@ Methods:
- <code title="delete /volumes/{id}">client.Volumes.<a href="https://pkg.go.dev/github.com/onkernel/hypeman-go#VolumeService.Delete">Delete</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>) <a href="https://pkg.go.dev/builtin#error">error</a></code>
- <code title="get /volumes/{id}">client.Volumes.<a href="https://pkg.go.dev/github.com/onkernel/hypeman-go#VolumeService.Get">Get</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>) (<a href="https://pkg.go.dev/github.com/onkernel/hypeman-go">hypeman</a>.<a href="https://pkg.go.dev/github.com/onkernel/hypeman-go#Volume">Volume</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>

# Devices

Response Types:

- <a href="https://pkg.go.dev/github.com/onkernel/hypeman-go">hypeman</a>.<a href="https://pkg.go.dev/github.com/onkernel/hypeman-go#AvailableDevice">AvailableDevice</a>
- <a href="https://pkg.go.dev/github.com/onkernel/hypeman-go">hypeman</a>.<a href="https://pkg.go.dev/github.com/onkernel/hypeman-go#Device">Device</a>
- <a href="https://pkg.go.dev/github.com/onkernel/hypeman-go">hypeman</a>.<a href="https://pkg.go.dev/github.com/onkernel/hypeman-go#DeviceType">DeviceType</a>

Methods:

- <code title="post /devices">client.Devices.<a href="https://pkg.go.dev/github.com/onkernel/hypeman-go#DeviceService.New">New</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, body <a href="https://pkg.go.dev/github.com/onkernel/hypeman-go">hypeman</a>.<a href="https://pkg.go.dev/github.com/onkernel/hypeman-go#DeviceNewParams">DeviceNewParams</a>) (<a href="https://pkg.go.dev/github.com/onkernel/hypeman-go">hypeman</a>.<a href="https://pkg.go.dev/github.com/onkernel/hypeman-go#Device">Device</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
- <code title="get /devices/{id}">client.Devices.<a href="https://pkg.go.dev/github.com/onkernel/hypeman-go#DeviceService.Get">Get</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>) (<a href="https://pkg.go.dev/github.com/onkernel/hypeman-go">hypeman</a>.<a href="https://pkg.go.dev/github.com/onkernel/hypeman-go#Device">Device</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
- <code title="get /devices">client.Devices.<a href="https://pkg.go.dev/github.com/onkernel/hypeman-go#DeviceService.List">List</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>) ([]<a href="https://pkg.go.dev/github.com/onkernel/hypeman-go">hypeman</a>.<a href="https://pkg.go.dev/github.com/onkernel/hypeman-go#Device">Device</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
- <code title="delete /devices/{id}">client.Devices.<a href="https://pkg.go.dev/github.com/onkernel/hypeman-go#DeviceService.Delete">Delete</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>) <a href="https://pkg.go.dev/builtin#error">error</a></code>
- <code title="get /devices/available">client.Devices.<a href="https://pkg.go.dev/github.com/onkernel/hypeman-go#DeviceService.ListAvailable">ListAvailable</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>) ([]<a href="https://pkg.go.dev/github.com/onkernel/hypeman-go">hypeman</a>.<a href="https://pkg.go.dev/github.com/onkernel/hypeman-go#AvailableDevice">AvailableDevice</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>

# Ingresses

Params Types:
Expand Down
2 changes: 2 additions & 0 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ type Client struct {
Images ImageService
Instances InstanceService
Volumes VolumeService
Devices DeviceService
Ingresses IngressService
}

Expand Down Expand Up @@ -50,6 +51,7 @@ func NewClient(opts ...option.RequestOption) (r Client) {
r.Images = NewImageService(opts...)
r.Instances = NewInstanceService(opts...)
r.Volumes = NewVolumeService(opts...)
r.Devices = NewDeviceService(opts...)
r.Ingresses = NewIngressService(opts...)

return
Expand Down
198 changes: 198 additions & 0 deletions device.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

package hypeman

import (
"context"
"errors"
"fmt"
"net/http"
"slices"
"time"

"github.com/onkernel/hypeman-go/internal/apijson"
"github.com/onkernel/hypeman-go/internal/requestconfig"
"github.com/onkernel/hypeman-go/option"
"github.com/onkernel/hypeman-go/packages/param"
"github.com/onkernel/hypeman-go/packages/respjson"
)

// DeviceService contains methods and other services that help with interacting
// with the hypeman API.
//
// Note, unlike clients, this service does not read variables from the environment
// automatically. You should not instantiate this service directly, and instead use
// the [NewDeviceService] method instead.
type DeviceService struct {
Options []option.RequestOption
}

// NewDeviceService generates a new service that applies the given options to each
// request. These options are applied after the parent client's options (if there
// is one), and before any request-specific options.
func NewDeviceService(opts ...option.RequestOption) (r DeviceService) {
r = DeviceService{}
r.Options = opts
return
}

// Register a device for passthrough
func (r *DeviceService) New(ctx context.Context, body DeviceNewParams, opts ...option.RequestOption) (res *Device, err error) {
opts = slices.Concat(r.Options, opts)
path := "devices"
err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...)
return
}

// Get device details
func (r *DeviceService) Get(ctx context.Context, id string, opts ...option.RequestOption) (res *Device, err error) {
opts = slices.Concat(r.Options, opts)
if id == "" {
err = errors.New("missing required id parameter")
return
}
path := fmt.Sprintf("devices/%s", id)
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...)
return
}

// List registered devices
func (r *DeviceService) List(ctx context.Context, opts ...option.RequestOption) (res *[]Device, err error) {
opts = slices.Concat(r.Options, opts)
path := "devices"
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...)
return
}

// Unregister device
func (r *DeviceService) Delete(ctx context.Context, id string, opts ...option.RequestOption) (err error) {
opts = slices.Concat(r.Options, opts)
opts = append([]option.RequestOption{option.WithHeader("Accept", "*/*")}, opts...)
if id == "" {
err = errors.New("missing required id parameter")
return
}
path := fmt.Sprintf("devices/%s", id)
err = requestconfig.ExecuteNewRequest(ctx, http.MethodDelete, path, nil, nil, opts...)
return
}

// Discover passthrough-capable devices on host
func (r *DeviceService) ListAvailable(ctx context.Context, opts ...option.RequestOption) (res *[]AvailableDevice, err error) {
opts = slices.Concat(r.Options, opts)
path := "devices/available"
err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...)
return
}

type AvailableDevice struct {
// PCI device ID (hex)
DeviceID string `json:"device_id,required"`
// IOMMU group number
IommuGroup int64 `json:"iommu_group,required"`
// PCI address
PciAddress string `json:"pci_address,required"`
// PCI vendor ID (hex)
VendorID string `json:"vendor_id,required"`
// Currently bound driver (null if none)
CurrentDriver string `json:"current_driver,nullable"`
// Human-readable device name
DeviceName string `json:"device_name"`
// Human-readable vendor name
VendorName string `json:"vendor_name"`
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
JSON struct {
DeviceID respjson.Field
IommuGroup respjson.Field
PciAddress respjson.Field
VendorID respjson.Field
CurrentDriver respjson.Field
DeviceName respjson.Field
VendorName respjson.Field
ExtraFields map[string]respjson.Field
raw string
} `json:"-"`
}

// Returns the unmodified JSON received from the API
func (r AvailableDevice) RawJSON() string { return r.JSON.raw }
func (r *AvailableDevice) UnmarshalJSON(data []byte) error {
return apijson.UnmarshalRoot(data, r)
}

type Device struct {
// Auto-generated unique identifier (CUID2 format)
ID string `json:"id,required"`
// Whether the device is currently bound to the vfio-pci driver, which is required
// for VM passthrough.
//
// - true: Device is bound to vfio-pci and ready for (or currently in use by) a VM.
// The device's native driver has been unloaded.
// - false: Device is using its native driver (e.g., nvidia) or no driver. Hypeman
// will automatically bind to vfio-pci when attaching to an instance.
BoundToVfio bool `json:"bound_to_vfio,required"`
// Registration timestamp (RFC3339)
CreatedAt time.Time `json:"created_at,required" format:"date-time"`
// PCI device ID (hex)
DeviceID string `json:"device_id,required"`
// IOMMU group number
IommuGroup int64 `json:"iommu_group,required"`
// PCI address
PciAddress string `json:"pci_address,required"`
// Type of PCI device
//
// Any of "gpu", "pci".
Type DeviceType `json:"type,required"`
// PCI vendor ID (hex)
VendorID string `json:"vendor_id,required"`
// Instance ID if attached
AttachedTo string `json:"attached_to,nullable"`
// Device name (user-provided or auto-generated from PCI address)
Name string `json:"name"`
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
JSON struct {
ID respjson.Field
BoundToVfio respjson.Field
CreatedAt respjson.Field
DeviceID respjson.Field
IommuGroup respjson.Field
PciAddress respjson.Field
Type respjson.Field
VendorID respjson.Field
AttachedTo respjson.Field
Name respjson.Field
ExtraFields map[string]respjson.Field
raw string
} `json:"-"`
}

// Returns the unmodified JSON received from the API
func (r Device) RawJSON() string { return r.JSON.raw }
func (r *Device) UnmarshalJSON(data []byte) error {
return apijson.UnmarshalRoot(data, r)
}

// Type of PCI device
type DeviceType string

const (
DeviceTypeGPU DeviceType = "gpu"
DeviceTypePci DeviceType = "pci"
)

type DeviceNewParams struct {
// PCI address of the device (required, e.g., "0000:a2:00.0")
PciAddress string `json:"pci_address,required"`
// Optional globally unique device name. If not provided, a name is auto-generated
// from the PCI address (e.g., "pci-0000-a2-00-0")
Name param.Opt[string] `json:"name,omitzero"`
paramObj
}

func (r DeviceNewParams) MarshalJSON() (data []byte, err error) {
type shadow DeviceNewParams
return param.MarshalObject(r, (*shadow)(&r))
}
func (r *DeviceNewParams) UnmarshalJSON(data []byte) error {
return apijson.UnmarshalRoot(data, r)
}
Loading