Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
2e5d33c
feat(storage-box): allow sorting in list opt
lukasmetzner Oct 9, 2025
2510f6f
feat(storage-box): stats not nullable
lukasmetzner Oct 9, 2025
bcbbebc
refactor(storage-box): make username required nullable
lukasmetzner Oct 9, 2025
f1c6777
feat(storage-box): access settings can be omitted in create opts
lukasmetzner Oct 9, 2025
861ff78
feat(subaccount): query by username and sort parameters
lukasmetzner Oct 9, 2025
40cd3ca
feat(snapshot): sort list and filter by is_automatic
lukasmetzner Oct 9, 2025
e9ec3c2
refactor(snapshot): remove todo as preimplemented api change in hclou…
lukasmetzner Oct 9, 2025
46e6809
feat(storage-box): make name optional in update opts
lukasmetzner Oct 9, 2025
2064044
style(schema-gen): group interface methods
lukasmetzner Oct 9, 2025
10fb71f
feat(storage-box): create opts location id or name
lukasmetzner Oct 9, 2025
d0e358a
feat(subaccount): remove home directory from access settings
lukasmetzner Oct 9, 2025
fc565e5
feat(subaccount): change home directory action
lukasmetzner Oct 9, 2025
f131c1a
feat(subaccount): get by username and get by id or username
lukasmetzner Oct 9, 2025
eb10d53
docs: missing schema docstrings
lukasmetzner Oct 9, 2025
fc7f2ce
feat(storage-box): accept snapshot id or name for rollback action
lukasmetzner Oct 9, 2025
d0609ae
docs: add relative links to types
lukasmetzner Oct 9, 2025
a02dfa1
docs(storage-box): missing schema docstrings
lukasmetzner Oct 9, 2025
891f12d
fix(subaccount): home directory should be required
lukasmetzner Oct 9, 2025
9830b68
test: improve test coverage
lukasmetzner Oct 9, 2025
88e0f31
fix(storage-box): remove pointer from name in update call
lukasmetzner Oct 10, 2025
9694b91
feat(snapshot): allow labels in create opts
lukasmetzner Oct 10, 2025
ac0c7d3
refactor(storage-box): simplify tests (#746)
lukasmetzner Oct 16, 2025
97ff733
feat(storage-box): require minute and hour
lukasmetzner Oct 16, 2025
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
4 changes: 4 additions & 0 deletions hcloud/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -558,3 +558,7 @@ func SchemaFromStorageBoxSubaccountResetPasswordOpts(opts StorageBoxSubaccountRe
func SchemaFromStorageBoxSubaccountUpdateAccessSettingsOpts(opts StorageBoxSubaccountAccessSettingsUpdateOpts) schema.StorageBoxSubaccountUpdateAccessSettingsRequest {
return c.SchemaFromStorageBoxSubaccountUpdateAccessSettingsOpts(opts)
}

func SchemaFromStorageBoxSubaccountChangeHomeDirectoryOpts(opts StorageBoxSubaccountChangeHomeDirectoryOpts) schema.StorageBoxSubaccountChangeHomeDirectoryRequest {
return c.SchemaFromStorageBoxSubaccountChangeHomeDirectoryOpts(opts)
}
57 changes: 33 additions & 24 deletions hcloud/schema/storage_box.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,25 @@ package schema

import "time"

// StorageBox defines the schema of a storage box.
// StorageBox defines the schema of a Storage Box.
type StorageBox struct {
ID int64 `json:"id"`
Username *string `json:"username,omitempty"`
Username *string `json:"username"`
Status string `json:"status"`
Name string `json:"name"`
StorageBoxType StorageBoxType `json:"storage_box_type"`
Location Location `json:"location"`
AccessSettings StorageBoxAccessSettings `json:"access_settings"`
Server *string `json:"server"`
System *string `json:"system"`
Stats *StorageBoxStats `json:"stats"`
Stats StorageBoxStats `json:"stats"`
Labels map[string]string `json:"labels"`
Protection StorageBoxProtection `json:"protection"`
SnapshotPlan *StorageBoxSnapshotPlan `json:"snapshot_plan"`
Created time.Time `json:"created"`
}

// StorageBoxAccessSettings defines the schema of a storage box's access settings.
// StorageBoxAccessSettings defines the schema of a Storage Box's access settings.
type StorageBoxAccessSettings struct {
ReachableExternally bool `json:"reachable_externally"`
SambaEnabled bool `json:"samba_enabled"`
Expand All @@ -29,19 +29,19 @@ type StorageBoxAccessSettings struct {
ZFSEnabled bool `json:"zfs_enabled"`
}

// StorageBoxStats defines the schema of a storage box's disk usage statistics.
// StorageBoxStats defines the schema of a Storage Box's disk usage statistics.
type StorageBoxStats struct {
Size uint64 `json:"size"`
SizeData uint64 `json:"size_data"`
SizeSnapshots uint64 `json:"size_snapshots"`
}

// StorageBoxProtection defines the schema of a storage box's resource protection.
// StorageBoxProtection defines the schema of a Storage Box's resource protection.
type StorageBoxProtection struct {
Delete bool `json:"delete"`
}

// StorageBoxSnapshotPlan defines the schema of a storage box's snapshot plan.
// StorageBoxSnapshotPlan defines the schema of a Storage Box's snapshot plan.
type StorageBoxSnapshotPlan struct {
MaxSnapshots int `json:"max_snapshots"`
Minute *int `json:"minute,omitempty"`
Expand All @@ -51,27 +51,27 @@ type StorageBoxSnapshotPlan struct {
}

// StorageBoxGetResponse defines the schema of the response when
// retrieving a single storage box.
// retrieving a single Storage Box.
type StorageBoxGetResponse struct {
StorageBox StorageBox `json:"storage_box"`
}

// StorageBoxListResponse defines the schema of the response when
// listing storage boxes.
// listing Storage Boxes.
type StorageBoxListResponse struct {
StorageBoxes []StorageBox `json:"storage_boxes"`
}

// StorageBoxCreateRequest defines the schema for the request to
// create a storage box.
// create a Storage Box.
type StorageBoxCreateRequest struct {
Name string `json:"name"`
StorageBoxType IDOrName `json:"storage_box_type"`
Location string `json:"location"`
Labels *map[string]string `json:"labels,omitempty"`
Password string `json:"password"`
SSHKeys []string `json:"ssh_keys,omitempty"`
AccessSettings StorageBoxCreateRequestAccessSettings `json:"access_settings,omitempty"`
Name string `json:"name"`
StorageBoxType IDOrName `json:"storage_box_type"`
Location IDOrName `json:"location"`
Labels *map[string]string `json:"labels,omitempty"`
Password string `json:"password"`
SSHKeys []string `json:"ssh_keys,omitempty"`
AccessSettings *StorageBoxCreateRequestAccessSettings `json:"access_settings,omitempty"`
}

type StorageBoxCreateRequestAccessSettings struct {
Expand All @@ -83,39 +83,46 @@ type StorageBoxCreateRequestAccessSettings struct {
}

// StorageBoxCreateResponse defines the schema of the response when
// creating a storage box.
// creating a Storage Box.
type StorageBoxCreateResponse struct {
StorageBox StorageBox `json:"storage_box"`
Action Action `json:"action"`
}

// StorageBoxUpdateRequest defines the schema of the request to update a storage box.
// StorageBoxUpdateRequest defines the schema of the request to update a Storage Box.
type StorageBoxUpdateRequest struct {
Name *string `json:"name,omitempty"`
Name string `json:"name,omitempty"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change feels backward. The fields in update requests will become optional for all three resources.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pointer was orignally there, because the API allowed empty strings to be set as a Storage Box name. This won't be the case in the future and an empty name will be ignored.

I thought this makes it somewhat easier to the user, as a pointer is not required.

We have a mixed pattern in the codebase, so I was unsure what the best option is. Both are fine for me.

// StorageBoxUpdateRequest defines the schema of the request to update a Storage Box.
type StorageBoxUpdateRequest struct {
	Name   string             `json:"name,omitempty"`
        // ...
}

// NetworkUpdateRequest defines the schema of the request to update a network.
type NetworkUpdateRequest struct {
	Name                  string             `json:"name,omitempty"`
        // ...
}

type LoadBalancerUpdateRequest struct {
	Name   *string            `json:"name,omitempty"`
        // ...
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer without pointer, reduces the complexity.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@apricote I would go ahead and merge this now, to proceed with the other review points in the main PR. We can discuss this topic there again, if you want.

Labels *map[string]string `json:"labels,omitempty"`
}

// StorageBoxUpdateResponse defines the schema of the response when updating a storage box.
// StorageBoxUpdateResponse defines the schema of the response when updating a Storage Box.
type StorageBoxUpdateResponse struct {
StorageBox StorageBox `json:"storage_box"`
}

// StorageBoxFoldersResponse defines the schema of the response when listing folders in a Storage Box.
type StorageBoxFoldersResponse struct {
Folders []string `json:"folders"`
}

// StorageBoxChangeProtectionRequest defines the schema of the request to change the
// resource protection of a Storage Box.
type StorageBoxChangeProtectionRequest struct {
Delete bool `json:"delete"`
}

// StorageBoxChangeTypeRequest defines the schema of the request to change the type of a Storage Box.
type StorageBoxChangeTypeRequest struct {
StorageBoxType IDOrName `json:"storage_box_type"`
}

// StorageBoxChangeTypeResponse defines the schema of the response when changing the type of a Storage Box.
type StorageBoxResetPasswordRequest struct {
Password string `json:"password"`
}

// StorageBoxUpdateAccessSettingsRequest defines the schema of the request when updating
// a Storage Box's access settings.
type StorageBoxUpdateAccessSettingsRequest struct {
ReachableExternally *bool `json:"reachable_externally"`
SambaEnabled *bool `json:"samba_enabled"`
Expand All @@ -124,14 +131,16 @@ type StorageBoxUpdateAccessSettingsRequest struct {
ZFSEnabled *bool `json:"zfs_enabled"`
}

// StorageBoxRollbackSnapshotRequest defines the schema of the request to roll back a Storage Box to a snapshot.
type StorageBoxRollbackSnapshotRequest struct {
SnapshotID int64 `json:"snapshot_id"`
Snapshot IDOrName `json:"snapshot"`
}

// StorageBoxEnableSnapshotPlanRequest defines the schema of the request to enable a snapshot plan for a Storage Box.
type StorageBoxEnableSnapshotPlanRequest struct {
MaxSnapshots int `json:"max_snapshots"`
Minute *int `json:"minute"`
Hour *int `json:"hour"`
Minute int `json:"minute"`
Hour int `json:"hour"`
DayOfWeek *int `json:"day_of_week"`
DayOfMonth *int `json:"day_of_month"`
}
4 changes: 2 additions & 2 deletions hcloud/schema/storage_box_snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ type StorageBoxSnapshotListResponse struct {

// StorageBoxSnapshotCreateRequest defines the schema of the request to create a Storage Box snapshot.
type StorageBoxSnapshotCreateRequest struct {
Description *string `json:"description,omitempty"`
Description *string `json:"description,omitempty"`
Labels map[string]string `json:"labels,omitempty"`
}

// StorageBoxSnapshotCreateResponse defines the schema of the response when creating a Storage Box snapshot.
Expand All @@ -41,7 +42,6 @@ type StorageBoxSnapshotCreateResponse struct {
Action Action `json:"action"`
}

// TODO: Both are required by the spec? Why?
// StorageBoxSnapshotUpdateRequest defines the schema of the request to update a Storage Box snapshot.
type StorageBoxSnapshotUpdateRequest struct {
Description *string `json:"description,omitempty"`
Expand Down
26 changes: 19 additions & 7 deletions hcloud/schema/storage_box_subaccount.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ type StorageBoxSubaccountCreateRequest struct {
Labels map[string]string `json:"labels,omitempty"`
}

// StorageBoxSubaccountCreateRequestAccessSettings defines the schema of the access settings in the request when creating a Storage Box subaccount.
// StorageBoxSubaccountCreateRequestAccessSettings defines the schema of the access settings in the
// request when creating a Storage Box subaccount.
type StorageBoxSubaccountCreateRequestAccessSettings struct {
ReachableExternally *bool `json:"reachable_externally,omitempty"`
Readonly *bool `json:"readonly,omitempty"`
Expand All @@ -58,6 +59,8 @@ type StorageBoxSubaccountCreateResponse struct {
Action Action `json:"action"`
}

// StorageBoxSubaccountCreateResponseSubaccount defines the schema of the subaccount in the response
// when creating a Storage Box subaccount.
type StorageBoxSubaccountCreateResponseSubaccount struct {
ID int64 `json:"id"`
StorageBox int64 `json:"storage_box"`
Expand All @@ -74,15 +77,24 @@ type StorageBoxSubaccountUpdateResponse struct {
Subaccount StorageBoxSubaccount `json:"subaccount"`
}

// StorageBoxSubaccountResetPasswordRequest defines the schema of the request when resetting a
// Storage Box subaccount's password.
type StorageBoxSubaccountResetPasswordRequest struct {
Password string `json:"password"`
}

// StorageBoxSubaccountUpdateAccessSettingsRequest defines the schema of the request when updating
// Storage Box subaccount's access settings.
type StorageBoxSubaccountUpdateAccessSettingsRequest struct {
HomeDirectory *string `json:"home_directory,omitempty"`
ReachableExternally *bool `json:"reachable_externally,omitempty"`
Readonly *bool `json:"readonly,omitempty"`
SambaEnabled *bool `json:"samba_enabled,omitempty"`
SSHEnabled *bool `json:"ssh_enabled,omitempty"`
WebDAVEnabled *bool `json:"webdav_enabled,omitempty"`
ReachableExternally *bool `json:"reachable_externally,omitempty"`
Readonly *bool `json:"readonly,omitempty"`
SambaEnabled *bool `json:"samba_enabled,omitempty"`
SSHEnabled *bool `json:"ssh_enabled,omitempty"`
WebDAVEnabled *bool `json:"webdav_enabled,omitempty"`
}

// StorageBoxSubaccountChangeHomeDirectoryRequest defines the schema of the request when changing
// the home directory of a Storage Box subaccount.
type StorageBoxSubaccountChangeHomeDirectoryRequest struct {
HomeDirectory string `json:"home_directory"`
}
46 changes: 10 additions & 36 deletions hcloud/schema_gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ You can find a documentation of goverter here: https://goverter.jmattheis.de/
// goverter:extend int64FromFloatingIP
// goverter:extend storageBoxFromInt64
// goverter:extend int64FromStorageBox
// goverter:extend int64FromStorageBoxSnapshot
// goverter:extend mapFromFloatingIPDNSPtrSchema
// goverter:extend floatingIPDNSPtrSchemaFromMap
// goverter:extend mapFromPrimaryIPDNSPtrSchema
Expand Down Expand Up @@ -391,61 +390,43 @@ type converter interface {
SchemaFromZoneRRSetAddRecordsOpts(ZoneRRSetAddRecordsOpts) schema.ZoneRRSetAddRecordsRequest
SchemaFromZoneRRSetRemoveRecordsOpts(ZoneRRSetRemoveRecordsOpts) schema.ZoneRRSetRemoveRecordsRequest

// StorageBoxType
// goverter:map Pricings Prices
SchemaFromStorageBoxType(*StorageBoxType) schema.StorageBoxType
// StorageBoxType conversions
// goverter:map Prices Pricings
StorageBoxTypeFromSchema(schema.StorageBoxType) *StorageBoxType

// StorageBox conversions
// StorageBox
StorageBoxFromSchema(schema.StorageBox) *StorageBox

// goverter:map DayOfWeek | mapStorageBoxIntPtrToWeekdayPtr
StorageBoxSnapshotPlanFromSchema(schema.StorageBoxSnapshotPlan) StorageBoxSnapshotPlan

SchemaFromStorageBox(*StorageBox) schema.StorageBox

SchemaFromStorageBoxCreateOpts(StorageBoxCreateOpts) schema.StorageBoxCreateRequest

// goverter:map Name | mapEmptyStringToNil
SchemaFromStorageBoxUpdateOpts(StorageBoxUpdateOpts) schema.StorageBoxUpdateRequest

StorageBoxSnapshotFromSchema(schema.StorageBoxSnapshot) *StorageBoxSnapshot

SchemaFromStorageBoxSnapshot(*StorageBoxSnapshot) schema.StorageBoxSnapshot

SchemaFromStorageBoxSnapshotCreateOpts(StorageBoxSnapshotCreateOpts) schema.StorageBoxSnapshotCreateRequest

SchemaFromStorageBoxSnapshotUpdateOpts(StorageBoxSnapshotUpdateOpts) schema.StorageBoxSnapshotUpdateRequest

SchemaFromStorageBoxChangeProtectionOpts(StorageBoxChangeProtectionOpts) schema.StorageBoxChangeProtectionRequest

SchemaFromStorageBoxChangeTypeOpts(StorageBoxChangeTypeOpts) schema.StorageBoxChangeTypeRequest

SchemaFromStorageBoxResetPasswordOpts(StorageBoxResetPasswordOpts) schema.StorageBoxResetPasswordRequest

SchemaFromStorageBoxUpdateAccessSettingsOpts(StorageBoxUpdateAccessSettingsOpts) schema.StorageBoxUpdateAccessSettingsRequest

// goverter:map Snapshot SnapshotID
SchemaFromStorageBoxRollbackSnapshotOpts(StorageBoxRollbackSnapshotOpts) schema.StorageBoxRollbackSnapshotRequest

// goverter:map DayOfWeek | mapStorageBoxWeekdayPtrToIntPtr
SchemaFromStorageBoxEnableSnapshotPlanOpts(StorageBoxEnableSnapshotPlanOpts) schema.StorageBoxEnableSnapshotPlanRequest

StorageBoxSubaccountFromSchema(schema.StorageBoxSubaccount) *StorageBoxSubaccount
// StorageBoxSnapshot
StorageBoxSnapshotFromSchema(schema.StorageBoxSnapshot) *StorageBoxSnapshot
SchemaFromStorageBoxSnapshot(*StorageBoxSnapshot) schema.StorageBoxSnapshot
SchemaFromStorageBoxSnapshotCreateOpts(StorageBoxSnapshotCreateOpts) schema.StorageBoxSnapshotCreateRequest
SchemaFromStorageBoxSnapshotUpdateOpts(StorageBoxSnapshotUpdateOpts) schema.StorageBoxSnapshotUpdateRequest

// StorageBoxSubaccount
StorageBoxSubaccountFromSchema(schema.StorageBoxSubaccount) *StorageBoxSubaccount
SchemaFromStorageBoxSubaccount(*StorageBoxSubaccount) schema.StorageBoxSubaccount

SchemaFromStorageBoxSubaccountCreateOpts(StorageBoxSubaccountCreateOpts) schema.StorageBoxSubaccountCreateRequest

SchemaFromStorageBoxSubaccountUpdateOpts(StorageBoxSubaccountUpdateOpts) schema.StorageBoxSubaccountUpdateRequest

// goverter:ignoreMissing
StorageBoxSubaccountFromCreateResponse(schema.StorageBoxSubaccountCreateResponseSubaccount) *StorageBoxSubaccount

SchemaFromStorageBoxSubaccountResetPasswordOpts(StorageBoxSubaccountResetPasswordOpts) schema.StorageBoxSubaccountResetPasswordRequest

SchemaFromStorageBoxSubaccountUpdateAccessSettingsOpts(StorageBoxSubaccountAccessSettingsUpdateOpts) schema.StorageBoxSubaccountUpdateAccessSettingsRequest
SchemaFromStorageBoxSubaccountChangeHomeDirectoryOpts(StorageBoxSubaccountChangeHomeDirectoryOpts) schema.StorageBoxSubaccountChangeHomeDirectoryRequest
}

func schemaActionErrorFromAction(a Action) *schema.ActionError {
Expand Down Expand Up @@ -659,13 +640,6 @@ func int64FromStorageBox(sb *StorageBox) int64 {
return sb.ID
}

func int64FromStorageBoxSnapshot(sbs *StorageBoxSnapshot) int64 {
if sbs == nil {
return 0
}
return sbs.ID
}

func firewallStatusFromSchemaServerFirewall(fw schema.ServerFirewall) *ServerFirewallStatus {
return &ServerFirewallStatus{
Firewall: Firewall{ID: fw.ID},
Expand Down
Loading