Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add ServerClient.RebuildWithResult to return root password #245

Merged
merged 2 commits into from
Mar 6, 2023
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: 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