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
3 changes: 3 additions & 0 deletions hcloud/schema/storage_box_subaccount.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import "time"
// StorageBoxSubaccount defines the schema of a Storage Box subaccount.
type StorageBoxSubaccount struct {
ID int64 `json:"id"`
Name string `json:"name"`
Username string `json:"username"`
HomeDirectory string `json:"home_directory"`
Server string `json:"server"`
Expand Down Expand Up @@ -36,6 +37,7 @@ type StorageBoxSubaccountListResponse struct {

// StorageBoxSubaccountCreateRequest defines the schema of the request when creating a Storage Box subaccount.
type StorageBoxSubaccountCreateRequest struct {
Name string `json:"name,omitempty"`
HomeDirectory string `json:"home_directory"`
Password string `json:"password"`
Description string `json:"description,omitempty"`
Expand Down Expand Up @@ -68,6 +70,7 @@ type StorageBoxSubaccountCreateResponseSubaccount struct {

// StorageBoxSubaccountUpdateRequest defines the schema of the request when updating a Storage Box subaccount.
type StorageBoxSubaccountUpdateRequest struct {
Name string `json:"name,omitempty"`
Description *string `json:"description,omitempty"`
Labels *map[string]string `json:"labels,omitempty"`
}
Expand Down
34 changes: 29 additions & 5 deletions hcloud/storage_box_subaccount.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
// See https://docs.hetzner.cloud/reference/hetzner#storage-box-subaccounts
type StorageBoxSubaccount struct {
ID int64
Name string
Username string
HomeDirectory string
Server string
Expand All @@ -34,7 +35,7 @@ type StorageBoxSubaccountAccessSettings struct {
WebDAVEnabled bool
}

// GetSubaccount retrieves a [StorageBoxSubaccount] either by its ID or by its username, depending on whether
// GetSubaccount retrieves a [StorageBoxSubaccount] either by its ID or by its name, depending on whether
// the input can be parsed as an integer. If no matching [StorageBoxSubaccount] is found, it returns nil.
//
// When fetching by ID, see https://docs.hetzner.cloud/reference/hetzner#storage-box-subaccounts-get-a-subaccount
Expand All @@ -44,17 +45,17 @@ type StorageBoxSubaccountAccessSettings struct {
func (c *StorageBoxClient) GetSubaccount(
ctx context.Context,
storageBox *StorageBox,
idOrUsername string,
idOrName string,
) (*StorageBoxSubaccount, *Response, error) {
return getByIDOrName(
ctx,
func(ctx context.Context, id int64) (*StorageBoxSubaccount, *Response, error) {
return c.GetSubaccountByID(ctx, storageBox, id)
},
func(ctx context.Context, username string) (*StorageBoxSubaccount, *Response, error) {
return c.GetSubaccountByUsername(ctx, storageBox, username)
func(ctx context.Context, name string) (*StorageBoxSubaccount, *Response, error) {
return c.GetSubaccountByName(ctx, storageBox, name)
},
idOrUsername,
idOrName,
)
}

Expand Down Expand Up @@ -84,6 +85,23 @@ func (c *StorageBoxClient) GetSubaccountByID(
return StorageBoxSubaccountFromSchema(respBody.Subaccount), resp, nil
}

// GetSubaccountByName retrieves a [StorageBoxSubaccount] by its name.
//
// See https://docs.hetzner.cloud/reference/hetzner#storage-box-subaccounts-list-subaccounts
//
// Experimental: [StorageBoxClient] is experimental, breaking changes may occur within minor releases.
func (c *StorageBoxClient) GetSubaccountByName(
ctx context.Context,
storageBox *StorageBox,
name string,
) (*StorageBoxSubaccount, *Response, error) {
return firstByName(name, func() ([]*StorageBoxSubaccount, *Response, error) {
return c.ListSubaccounts(ctx, storageBox, StorageBoxSubaccountListOpts{
Name: name,
})
})
}

// GetSubaccountByUsername retrieves a [StorageBoxSubaccount] by its username.
//
// See https://docs.hetzner.cloud/reference/hetzner#storage-box-subaccounts-list-subaccounts
Expand All @@ -104,12 +122,16 @@ func (c *StorageBoxClient) GetSubaccountByUsername(
// StorageBoxSubaccountListOpts represents the options for listing [StorageBoxSubaccount].
type StorageBoxSubaccountListOpts struct {
LabelSelector string
Name string
Username string
Sort []string
}

func (o StorageBoxSubaccountListOpts) values() url.Values {
vals := url.Values{}
if o.Name != "" {
vals.Add("name", o.Name)
}
if o.Username != "" {
vals.Add("username", o.Username)
}
Expand Down Expand Up @@ -175,6 +197,7 @@ func (c *StorageBoxClient) AllSubaccounts(

// StorageBoxSubaccountCreateOpts represents the options for creating a [StorageBoxSubaccount].
type StorageBoxSubaccountCreateOpts struct {
Name string
HomeDirectory string
Password string
Description string
Expand Down Expand Up @@ -228,6 +251,7 @@ func (c *StorageBoxClient) CreateSubaccount(

// StorageBoxSubaccountUpdateOpts represents the options for updating a [StorageBoxSubaccount].
type StorageBoxSubaccountUpdateOpts struct {
Name string
Description *string
Labels map[string]string
}
Expand Down
141 changes: 123 additions & 18 deletions hcloud/storage_box_subaccount_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
)

func TestStorageBoxClientGetSubaccount(t *testing.T) {
t.Run("GetSubaccount (ByID)", func(t *testing.T) {
t.Run("GetSubaccountByID", func(t *testing.T) {
ctx, server, client := makeTestUtils(t)

server.Expect([]mockutil.Request{
Expand All @@ -23,9 +23,10 @@ func TestStorageBoxClientGetSubaccount(t *testing.T) {
JSONRaw: `{
"subaccount": {
"id": 13,
"username": "my-user",
"home_directory": "/home/my-user",
"server": "my-server",
"name": "subaccount1",
"home_directory": "/home/subaccount1",
"username": "u516715-sub1",
"server": "u516715.your-storagebox.de",
"access_settings": {
"reachable_externally": true,
"readonly": false,
Expand Down Expand Up @@ -53,9 +54,10 @@ func TestStorageBoxClientGetSubaccount(t *testing.T) {
require.NotNil(t, subaccount)

assert.Equal(t, int64(13), subaccount.ID)
assert.Equal(t, "my-user", subaccount.Username)
assert.Equal(t, "/home/my-user", subaccount.HomeDirectory)
assert.Equal(t, "my-server", subaccount.Server)
assert.Equal(t, "subaccount1", subaccount.Name)
assert.Equal(t, "/home/subaccount1", subaccount.HomeDirectory)
assert.Equal(t, "u516715-sub1", subaccount.Username)
assert.Equal(t, "u516715.your-storagebox.de", subaccount.Server)
assert.True(t, subaccount.AccessSettings.ReachableExternally)
assert.False(t, subaccount.AccessSettings.Readonly)
assert.True(t, subaccount.AccessSettings.SambaEnabled)
Expand All @@ -66,7 +68,7 @@ func TestStorageBoxClientGetSubaccount(t *testing.T) {
assert.Equal(t, "prod", subaccount.Labels["environment"])
})

t.Run("GetSubaccount (not found)", func(t *testing.T) {
t.Run("GetSubaccountByID (not found)", func(t *testing.T) {
ctx, server, client := makeTestUtils(t)

server.Expect([]mockutil.Request{
Expand All @@ -92,12 +94,12 @@ func TestStorageBoxClientGetSubaccount(t *testing.T) {
assert.Equal(t, 404, resp.StatusCode)
})

t.Run("GetSubaccount (ByUsername)", func(t *testing.T) {
t.Run("GetSubaccountByName", func(t *testing.T) {
ctx, server, client := makeTestUtils(t)

server.Expect([]mockutil.Request{
{
Method: "GET", Path: "/storage_boxes/42/subaccounts?username=my-user",
Method: "GET", Path: "/storage_boxes/42/subaccounts?name=subaccount1",
Status: 200,
JSONRaw: `{
"subaccounts": [{ "id": 13 }]
Expand All @@ -107,15 +109,38 @@ func TestStorageBoxClientGetSubaccount(t *testing.T) {

storageBox := &StorageBox{ID: 42}

subaccount, resp, err := client.StorageBox.GetSubaccountByUsername(ctx, storageBox, "my-user")
subaccount, resp, err := client.StorageBox.GetSubaccountByName(ctx, storageBox, "subaccount1")
require.NoError(t, err)
require.NotNil(t, resp)
require.NotNil(t, subaccount)

assert.Equal(t, int64(13), subaccount.ID)
})

t.Run("GetSubbacount (IDOrName)", func(t *testing.T) {
t.Run("GetSubaccountByUsername", func(t *testing.T) {
ctx, server, client := makeTestUtils(t)

server.Expect([]mockutil.Request{
{
Method: "GET", Path: "/storage_boxes/42/subaccounts?username=u516715-sub1",
Status: 200,
JSONRaw: `{
"subaccounts": [{ "id": 13 }]
}`,
},
})

storageBox := &StorageBox{ID: 42}

subaccount, resp, err := client.StorageBox.GetSubaccountByUsername(ctx, storageBox, "u516715-sub1")
require.NoError(t, err)
require.NotNil(t, resp)
require.NotNil(t, subaccount)

assert.Equal(t, int64(13), subaccount.ID)
})

t.Run("GetSubaccount", func(t *testing.T) {
ctx, server, client := makeTestUtils(t)

server.Expect([]mockutil.Request{
Expand All @@ -127,7 +152,7 @@ func TestStorageBoxClientGetSubaccount(t *testing.T) {
}`,
},
{
Method: "GET", Path: "/storage_boxes/42/subaccounts?username=my-user",
Method: "GET", Path: "/storage_boxes/42/subaccounts?name=subaccount1",
Status: 200,
JSONRaw: `{
"subaccounts": [{ "id": 14 }]
Expand All @@ -144,7 +169,7 @@ func TestStorageBoxClientGetSubaccount(t *testing.T) {

assert.Equal(t, int64(13), subaccount.ID)

subaccount, resp, err = client.StorageBox.GetSubaccount(ctx, storageBox, "my-user")
subaccount, resp, err = client.StorageBox.GetSubaccount(ctx, storageBox, "subaccount1")
require.NoError(t, err)
require.NotNil(t, resp)
require.NotNil(t, subaccount)
Expand Down Expand Up @@ -223,7 +248,8 @@ func TestStorageBoxClientCreateSubaccount(t *testing.T) {
require.NoError(t, err)

expectedBody := `{
"home_directory": "/home/my-user",
"name": "subaccount1",
"home_directory": "/home/subaccount1",
"password": "my-password",
"access_settings": {
"reachable_externally": true,
Expand All @@ -249,7 +275,8 @@ func TestStorageBoxClientCreateSubaccount(t *testing.T) {
storageBox := &StorageBox{ID: 42}

opts := StorageBoxSubaccountCreateOpts{
HomeDirectory: "/home/my-user",
Name: "subaccount1",
HomeDirectory: "/home/subaccount1",
Password: "my-password",
Description: "This describes my subaccount",
AccessSettings: &StorageBoxSubaccountCreateOptsAccessSettings{
Expand All @@ -272,6 +299,46 @@ func TestStorageBoxClientCreateSubaccount(t *testing.T) {

assert.Equal(t, int64(42), subaccount.ID)
})

t.Run("CreateSubaccount (minimal)", func(t *testing.T) {
ctx, server, client := makeTestUtils(t)

server.Expect([]mockutil.Request{
{
Method: "POST", Path: "/storage_boxes/42/subaccounts",
Status: 201,
Want: func(t *testing.T, r *http.Request) {
body, err := io.ReadAll(r.Body)
require.NoError(t, err)

expectedBody := `{
"home_directory": "/home/subaccount1",
"password": "my-password"
}`
assert.JSONEq(t, expectedBody, string(body))
},
JSONRaw: `{
"subaccount": { "id": 42 },
"action": { "id": 12345 }
}`,
},
})

storageBox := &StorageBox{ID: 42}

opts := StorageBoxSubaccountCreateOpts{
HomeDirectory: "/home/subaccount1",
Password: "my-password",
}
result, _, err := client.StorageBox.CreateSubaccount(ctx, storageBox, opts)
require.NoError(t, err)
require.NotNil(t, result)

subaccount := result.Subaccount
require.NotNil(t, subaccount)

assert.Equal(t, int64(42), subaccount.ID)
})
}

func TestStorageBoxClientUpdateSubaccount(t *testing.T) {
Expand All @@ -287,6 +354,7 @@ func TestStorageBoxClientUpdateSubaccount(t *testing.T) {
require.NoError(t, err)

expectedBody := `{
"name": "subaccount1",
"labels": {
"environment": "prod",
"example.com/my": "label",
Expand All @@ -310,6 +378,7 @@ func TestStorageBoxClientUpdateSubaccount(t *testing.T) {
}

opts := StorageBoxSubaccountUpdateOpts{
Name: "subaccount1",
Description: Ptr("Updated description"),
Labels: map[string]string{
"environment": "prod",
Expand All @@ -324,6 +393,42 @@ func TestStorageBoxClientUpdateSubaccount(t *testing.T) {

assert.Equal(t, int64(13), subaccount.ID)
})

t.Run("UpdateSubaccount (minimal)", func(t *testing.T) {
ctx, server, client := makeTestUtils(t)

server.Expect([]mockutil.Request{
{
Method: "PUT", Path: "/storage_boxes/42/subaccounts/13",
Status: 200,
Want: func(t *testing.T, r *http.Request) {
body, err := io.ReadAll(r.Body)
require.NoError(t, err)

expectedBody := `{}`
assert.JSONEq(t, expectedBody, string(body))
},
JSONRaw: `{
"subaccount": { "id": 13 }
}`,
},
})

subaccount := &StorageBoxSubaccount{
ID: 13,
StorageBox: &StorageBox{
ID: 42,
},
}

opts := StorageBoxSubaccountUpdateOpts{}

subaccount, _, err := client.StorageBox.UpdateSubaccount(ctx, subaccount, opts)
require.NoError(t, err)
require.NotNil(t, subaccount)

assert.Equal(t, int64(13), subaccount.ID)
})
}

func TestStorageBoxClientDeleteSubaccount(t *testing.T) {
Expand Down Expand Up @@ -384,7 +489,7 @@ func TestStorageBoxClientResetSubaccountPassword(t *testing.T) {
require.NotNil(t, action)
}

func TestStorageBoxSubbacountUpdateAccessSettings(t *testing.T) {
func TestStorageBoxSubaccountUpdateAccessSettings(t *testing.T) {
ctx, server, client := makeTestUtils(t)

server.Expect([]mockutil.Request{
Expand Down Expand Up @@ -429,7 +534,7 @@ func TestStorageBoxSubbacountUpdateAccessSettings(t *testing.T) {
require.NotNil(t, action)
}

func TestStorageBoxSubbacountChangeHomeDirectory(t *testing.T) {
func TestStorageBoxSubaccountChangeHomeDirectory(t *testing.T) {
ctx, server, client := makeTestUtils(t)

server.Expect([]mockutil.Request{
Expand Down
Loading