Skip to content

Commit

Permalink
feat: add ServerClient.RebuildWithResult to return root password (#245)
Browse files Browse the repository at this point in the history
* feat: add ServerClient.RebuildWithResult to return root password

The existing method Serverclient.Rebuild did not return the root
password and there was no way to add it without breaking API
compatibility.

Closes #244

* chore: cleanup comments for ServerClient.Delete(WithResult)

- Comment should start with the method name
- Deprecated methods should contain "^Deprecated: xx" in the
  comment
- References to other symbols should use square brackets
  • Loading branch information
apricote authored Mar 6, 2023
1 parent 8ae14f3 commit 82f97cf
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 7 deletions.
3 changes: 2 additions & 1 deletion hcloud/schema/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,8 @@ type ServerActionRebuildRequest struct {
// ServerActionRebuildResponse defines the schema of the response when
// creating a rebuild server action.
type ServerActionRebuildResponse struct {
Action Action `json:"action"`
Action Action `json:"action"`
RootPassword *string `json:"root_password"`
}

// ServerActionAttachISORequest defines the schema for the request to
Expand Down
36 changes: 30 additions & 6 deletions hcloud/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -464,13 +464,14 @@ type ServerDeleteResult struct {
}

// Delete deletes a server.
// This method is deprecated, use ServerClient.DeleteWithResult instead.
//
// Deprecated: Use [ServerClient.DeleteWithResult] instead.
func (c *ServerClient) Delete(ctx context.Context, server *Server) (*Response, error) {
_, resp, err := c.DeleteWithResult(ctx, server)
return resp, err
}

// Delete deletes a server and returns the parsed response containing the action.
// DeleteWithResult deletes a server and returns the parsed response containing the action.
func (c *ServerClient) DeleteWithResult(ctx context.Context, server *Server) (*ServerDeleteResult, *Response, error) {
req, err := c.client.NewRequest(ctx, "DELETE", fmt.Sprintf("/servers/%d", server.ID), nil)
if err != nil {
Expand Down Expand Up @@ -756,8 +757,23 @@ type ServerRebuildOpts struct {
Image *Image
}

// ServerRebuildResult is the result of a create server call.
type ServerRebuildResult struct {
Action *Action
RootPassword string
}

// Rebuild rebuilds a server.
//
// Deprecated: Use [ServerClient.RebuildWithResult] instead.
func (c *ServerClient) Rebuild(ctx context.Context, server *Server, opts ServerRebuildOpts) (*Action, *Response, error) {
result, resp, err := c.RebuildWithResult(ctx, server, opts)

return result.Action, resp, err
}

// RebuildWithResult rebuilds a server.
func (c *ServerClient) RebuildWithResult(ctx context.Context, server *Server, opts ServerRebuildOpts) (ServerRebuildResult, *Response, error) {
reqBody := schema.ServerActionRebuildRequest{}
if opts.Image.ID != 0 {
reqBody.Image = opts.Image.ID
Expand All @@ -766,21 +782,29 @@ func (c *ServerClient) Rebuild(ctx context.Context, server *Server, opts ServerR
}
reqBodyData, err := json.Marshal(reqBody)
if err != nil {
return nil, nil, err
return ServerRebuildResult{}, nil, err
}

path := fmt.Sprintf("/servers/%d/actions/rebuild", server.ID)
req, err := c.client.NewRequest(ctx, "POST", path, bytes.NewReader(reqBodyData))
if err != nil {
return nil, nil, err
return ServerRebuildResult{}, nil, err
}

respBody := schema.ServerActionRebuildResponse{}
resp, err := c.client.Do(req, &respBody)
if err != nil {
return nil, resp, err
return ServerRebuildResult{}, resp, err
}
return ActionFromSchema(respBody.Action), resp, nil

result := ServerRebuildResult{
Action: ActionFromSchema(respBody.Action),
}
if respBody.RootPassword != nil {
result.RootPassword = *respBody.RootPassword
}

return result, resp, nil
}

// AttachISO attaches an ISO to a server.
Expand Down
77 changes: 77 additions & 0 deletions hcloud/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1522,6 +1522,83 @@ func TestServerClientRebuild(t *testing.T) {
})
}

func TestServerClientRebuildWithResult(t *testing.T) {
var (
ctx = context.Background()
server = &Server{ID: 1}
)

t.Run("with image ID", func(t *testing.T) {
env := newTestEnv()
defer env.Teardown()

env.Mux.HandleFunc("/servers/1/actions/rebuild", func(w http.ResponseWriter, r *http.Request) {
var reqBody schema.ServerActionRebuildRequest
if err := json.NewDecoder(r.Body).Decode(&reqBody); err != nil {
t.Fatal(err)
}
if id, ok := reqBody.Image.(float64); !ok || id != 1 {
t.Errorf("unexpected image ID: %v", reqBody.Image)
}
json.NewEncoder(w).Encode(schema.ServerActionRebuildResponse{
Action: schema.Action{
ID: 1,
},
RootPassword: Ptr("hetzner"),
})
})

opts := ServerRebuildOpts{
Image: &Image{ID: 1},
}
result, _, err := env.Client.Server.RebuildWithResult(ctx, server, opts)
if err != nil {
t.Fatal(err)
}
if result.Action.ID != 1 {
t.Errorf("unexpected action ID: %d", result.Action.ID)
}
if result.RootPassword != "hetzner" {
t.Errorf("unexpected root password: %s", result.RootPassword)
}
})

t.Run("with image name", func(t *testing.T) {
env := newTestEnv()
defer env.Teardown()

env.Mux.HandleFunc("/servers/1/actions/rebuild", func(w http.ResponseWriter, r *http.Request) {
var reqBody schema.ServerActionRebuildRequest
if err := json.NewDecoder(r.Body).Decode(&reqBody); err != nil {
t.Fatal(err)
}
if name, ok := reqBody.Image.(string); !ok || name != "debian-9" {
t.Errorf("unexpected image name: %v", reqBody.Image)
}
json.NewEncoder(w).Encode(schema.ServerActionRebuildResponse{
Action: schema.Action{
ID: 1,
},
RootPassword: nil,
})
})

opts := ServerRebuildOpts{
Image: &Image{Name: "debian-9"},
}
result, _, err := env.Client.Server.RebuildWithResult(ctx, server, opts)
if err != nil {
t.Fatal(err)
}
if result.Action.ID != 1 {
t.Errorf("unexpected action ID: %d", result.Action.ID)
}
if result.RootPassword != "" {
t.Errorf("unexpected root password: %s", result.RootPassword)
}
})
}

func TestServerClientAttachISO(t *testing.T) {
var (
ctx = context.Background()
Expand Down

0 comments on commit 82f97cf

Please sign in to comment.