diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 28e831b..3d2ac0b 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.0.3" + ".": "0.1.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 89ecdb6..0219fc6 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 18 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fhypeman-7c27e323412e72166bce2de104f1bf82b57197e05b686e94cd81d07e288bd558.yml -openapi_spec_hash: 4656d2b318d04a9fec0210897d76b505 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fhypeman-5e2239ba23ac3dbbc95b8993a491e99e9fd23fed2e6ea9cecb81b83bf34a00ff.yml +openapi_spec_hash: 4708504f9119289926b3341d083a1814 config_hash: 35db4c99791f175865381f13a8ad6075 diff --git a/CHANGELOG.md b/CHANGELOG.md index 48afd3e..89d4ebe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 0.1.0 (2025-11-26) + +Full Changelog: [v0.0.3...v0.1.0](https://github.com/onkernel/hypeman-go/compare/v0.0.3...v0.1.0) + +### Features + +* Network manager ([7864aba](https://github.com/onkernel/hypeman-go/commit/7864abadad29bcfbb61d2c35a7135ef2407d6c47)) + ## 0.0.3 (2025-11-19) Full Changelog: [v0.0.2...v0.0.3](https://github.com/onkernel/hypeman-go/compare/v0.0.2...v0.0.3) diff --git a/README.md b/README.md index 65dd46e..575df9a 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Or to pin the version: ```sh -go get -u 'github.com/onkernel/hypeman-go@v0.0.3' +go get -u 'github.com/onkernel/hypeman-go@v0.1.0' ``` diff --git a/api.md b/api.md index 7190793..81083cd 100644 --- a/api.md +++ b/api.md @@ -23,16 +23,9 @@ Methods: # Instances -Params Types: - -- hypeman.PortMappingParam -- hypeman.VolumeAttachmentParam - Response Types: - hypeman.Instance -- hypeman.PortMapping -- hypeman.VolumeAttachment Methods: diff --git a/instance.go b/instance.go index af316af..78f1bbd 100644 --- a/instance.go +++ b/instance.go @@ -4,7 +4,6 @@ package hypeman import ( "context" - "encoding/json" "errors" "fmt" "net/http" @@ -125,11 +124,11 @@ func (r *InstanceService) StreamLogsStreaming(ctx context.Context, id string, qu } type Instance struct { - // Unique identifier + // Auto-generated unique identifier (CUID2 format) ID string `json:"id,required"` // Creation timestamp (RFC3339) CreatedAt time.Time `json:"created_at,required" format:"date-time"` - // Image identifier + // OCI image reference Image string `json:"image,required"` // Human-readable name Name string `json:"name,required"` @@ -146,49 +145,40 @@ type Instance struct { State InstanceState `json:"state,required"` // Environment variables Env map[string]string `json:"env"` - // Fully qualified domain name - Fqdn string `json:"fqdn,nullable"` // Whether a snapshot exists for this instance HasSnapshot bool `json:"has_snapshot"` - // Configured maximum memory in MB - MemoryMaxMB int64 `json:"memory_max_mb"` - // Configured base memory in MB - MemoryMB int64 `json:"memory_mb"` - // Port mappings - PortMappings []PortMapping `json:"port_mappings"` - // Private IP address - PrivateIP string `json:"private_ip,nullable"` + // Hotplug memory size (human-readable) + HotplugSize string `json:"hotplug_size"` + // Network configuration of the instance + Network InstanceNetwork `json:"network"` + // Writable overlay disk size (human-readable) + OverlaySize string `json:"overlay_size"` + // Base memory size (human-readable) + Size string `json:"size"` // Start timestamp (RFC3339) StartedAt time.Time `json:"started_at,nullable" format:"date-time"` // Stop timestamp (RFC3339) StoppedAt time.Time `json:"stopped_at,nullable" format:"date-time"` - // Timeout configuration - TimeoutSeconds int64 `json:"timeout_seconds"` // Number of virtual CPUs Vcpus int64 `json:"vcpus"` - // Attached volumes - Volumes []VolumeAttachment `json:"volumes"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { - ID respjson.Field - CreatedAt respjson.Field - Image respjson.Field - Name respjson.Field - State respjson.Field - Env respjson.Field - Fqdn respjson.Field - HasSnapshot respjson.Field - MemoryMaxMB respjson.Field - MemoryMB respjson.Field - PortMappings respjson.Field - PrivateIP respjson.Field - StartedAt respjson.Field - StoppedAt respjson.Field - TimeoutSeconds respjson.Field - Vcpus respjson.Field - Volumes respjson.Field - ExtraFields map[string]respjson.Field - raw string + ID respjson.Field + CreatedAt respjson.Field + Image respjson.Field + Name respjson.Field + State respjson.Field + Env respjson.Field + HasSnapshot respjson.Field + HotplugSize respjson.Field + Network respjson.Field + OverlaySize respjson.Field + Size respjson.Field + StartedAt respjson.Field + StoppedAt respjson.Field + Vcpus respjson.Field + ExtraFields map[string]respjson.Field + raw string } `json:"-"` } @@ -217,136 +207,51 @@ const ( InstanceStateStandby InstanceState = "Standby" ) -type PortMapping struct { - // Port in the guest VM - GuestPort int64 `json:"guest_port,required"` - // Port on the host - HostPort int64 `json:"host_port,required"` - // Any of "tcp", "udp". - Protocol PortMappingProtocol `json:"protocol"` +// Network configuration of the instance +type InstanceNetwork struct { + // Whether instance is attached to the default network + Enabled bool `json:"enabled"` + // Assigned IP address (null if no network) + IP string `json:"ip,nullable"` + // Assigned MAC address (null if no network) + Mac string `json:"mac,nullable"` + // Network name (always "default" when enabled) + Name string `json:"name"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { - GuestPort respjson.Field - HostPort respjson.Field - Protocol respjson.Field + Enabled respjson.Field + IP respjson.Field + Mac respjson.Field + Name respjson.Field ExtraFields map[string]respjson.Field raw string } `json:"-"` } // Returns the unmodified JSON received from the API -func (r PortMapping) RawJSON() string { return r.JSON.raw } -func (r *PortMapping) UnmarshalJSON(data []byte) error { - return apijson.UnmarshalRoot(data, r) -} - -// ToParam converts this PortMapping to a PortMappingParam. -// -// Warning: the fields of the param type will not be present. ToParam should only -// be used at the last possible moment before sending a request. Test for this with -// PortMappingParam.Overrides() -func (r PortMapping) ToParam() PortMappingParam { - return param.Override[PortMappingParam](json.RawMessage(r.RawJSON())) -} - -type PortMappingProtocol string - -const ( - PortMappingProtocolTcp PortMappingProtocol = "tcp" - PortMappingProtocolUdp PortMappingProtocol = "udp" -) - -// The properties GuestPort, HostPort are required. -type PortMappingParam struct { - // Port in the guest VM - GuestPort int64 `json:"guest_port,required"` - // Port on the host - HostPort int64 `json:"host_port,required"` - // Any of "tcp", "udp". - Protocol PortMappingProtocol `json:"protocol,omitzero"` - paramObj -} - -func (r PortMappingParam) MarshalJSON() (data []byte, err error) { - type shadow PortMappingParam - return param.MarshalObject(r, (*shadow)(&r)) -} -func (r *PortMappingParam) UnmarshalJSON(data []byte) error { - return apijson.UnmarshalRoot(data, r) -} - -type VolumeAttachment struct { - // Path where volume is mounted in the guest - MountPath string `json:"mount_path,required"` - // Volume identifier - VolumeID string `json:"volume_id,required"` - // Whether volume is mounted read-only - Readonly bool `json:"readonly"` - // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. - JSON struct { - MountPath respjson.Field - VolumeID respjson.Field - Readonly respjson.Field - ExtraFields map[string]respjson.Field - raw string - } `json:"-"` -} - -// Returns the unmodified JSON received from the API -func (r VolumeAttachment) RawJSON() string { return r.JSON.raw } -func (r *VolumeAttachment) UnmarshalJSON(data []byte) error { - return apijson.UnmarshalRoot(data, r) -} - -// ToParam converts this VolumeAttachment to a VolumeAttachmentParam. -// -// Warning: the fields of the param type will not be present. ToParam should only -// be used at the last possible moment before sending a request. Test for this with -// VolumeAttachmentParam.Overrides() -func (r VolumeAttachment) ToParam() VolumeAttachmentParam { - return param.Override[VolumeAttachmentParam](json.RawMessage(r.RawJSON())) -} - -// The properties MountPath, VolumeID are required. -type VolumeAttachmentParam struct { - // Path where volume is mounted in the guest - MountPath string `json:"mount_path,required"` - // Volume identifier - VolumeID string `json:"volume_id,required"` - // Whether volume is mounted read-only - Readonly param.Opt[bool] `json:"readonly,omitzero"` - paramObj -} - -func (r VolumeAttachmentParam) MarshalJSON() (data []byte, err error) { - type shadow VolumeAttachmentParam - return param.MarshalObject(r, (*shadow)(&r)) -} -func (r *VolumeAttachmentParam) UnmarshalJSON(data []byte) error { +func (r InstanceNetwork) RawJSON() string { return r.JSON.raw } +func (r *InstanceNetwork) UnmarshalJSON(data []byte) error { return apijson.UnmarshalRoot(data, r) } type InstanceNewParams struct { - // Unique identifier for the instance (provided by caller) - ID string `json:"id,required"` - // Image identifier + // OCI image reference Image string `json:"image,required"` - // Human-readable name + // Human-readable name (lowercase letters, digits, and dashes only; cannot start or + // end with a dash) Name string `json:"name,required"` - // Maximum memory with hotplug in MB - MemoryMaxMB param.Opt[int64] `json:"memory_max_mb,omitzero"` - // Base memory in MB - MemoryMB param.Opt[int64] `json:"memory_mb,omitzero"` - // Timeout for scale-to-zero semantics - TimeoutSeconds param.Opt[int64] `json:"timeout_seconds,omitzero"` + // Additional memory for hotplug (human-readable format like "3GB", "1G") + HotplugSize param.Opt[string] `json:"hotplug_size,omitzero"` + // Writable overlay disk size (human-readable format like "10GB", "50G") + OverlaySize param.Opt[string] `json:"overlay_size,omitzero"` + // Base memory size (human-readable format like "1GB", "512MB", "2G") + Size param.Opt[string] `json:"size,omitzero"` // Number of virtual CPUs Vcpus param.Opt[int64] `json:"vcpus,omitzero"` // Environment variables Env map[string]string `json:"env,omitzero"` - // Port mappings from host to guest - PortMappings []PortMappingParam `json:"port_mappings,omitzero"` - // Volumes to attach - Volumes []VolumeAttachmentParam `json:"volumes,omitzero"` + // Network configuration for the instance + Network InstanceNewParamsNetwork `json:"network,omitzero"` paramObj } @@ -358,6 +263,21 @@ func (r *InstanceNewParams) UnmarshalJSON(data []byte) error { return apijson.UnmarshalRoot(data, r) } +// Network configuration for the instance +type InstanceNewParamsNetwork struct { + // Whether to attach instance to the default network + Enabled param.Opt[bool] `json:"enabled,omitzero"` + paramObj +} + +func (r InstanceNewParamsNetwork) MarshalJSON() (data []byte, err error) { + type shadow InstanceNewParamsNetwork + return param.MarshalObject(r, (*shadow)(&r)) +} +func (r *InstanceNewParamsNetwork) UnmarshalJSON(data []byte) error { + return apijson.UnmarshalRoot(data, r) +} + type InstanceStreamLogsParams struct { // Follow logs (stream with SSE) Follow param.Opt[bool] `query:"follow,omitzero" json:"-"` diff --git a/instance_test.go b/instance_test.go index 6a24de2..d88c1a6 100644 --- a/instance_test.go +++ b/instance_test.go @@ -27,27 +27,19 @@ func TestInstanceNewWithOptionalParams(t *testing.T) { option.WithAPIKey("My API Key"), ) _, err := client.Instances.New(context.TODO(), hypeman.InstanceNewParams{ - ID: "inst-abc123", - Image: "img-chrome-v1", + Image: "docker.io/library/alpine:latest", Name: "my-workload-1", Env: map[string]string{ "PORT": "3000", "NODE_ENV": "production", }, - MemoryMaxMB: hypeman.Int(4096), - MemoryMB: hypeman.Int(2048), - PortMappings: []hypeman.PortMappingParam{{ - GuestPort: 80, - HostPort: 8080, - Protocol: hypeman.PortMappingProtocolTcp, - }}, - TimeoutSeconds: hypeman.Int(7200), - Vcpus: hypeman.Int(2), - Volumes: []hypeman.VolumeAttachmentParam{{ - MountPath: "/mnt/data", - VolumeID: "vol-abc123", - Readonly: hypeman.Bool(true), - }}, + HotplugSize: hypeman.String("2GB"), + Network: hypeman.InstanceNewParamsNetwork{ + Enabled: hypeman.Bool(true), + }, + OverlaySize: hypeman.String("20GB"), + Size: hypeman.String("2GB"), + Vcpus: hypeman.Int(2), }) if err != nil { var apierr *hypeman.Error diff --git a/internal/version.go b/internal/version.go index b5b3e63..02eac73 100644 --- a/internal/version.go +++ b/internal/version.go @@ -2,4 +2,4 @@ package internal -const PackageVersion = "0.0.3" // x-release-please-version +const PackageVersion = "0.1.0" // x-release-please-version