Skip to content

Commit

Permalink
Add create multiple servers
Browse files Browse the repository at this point in the history
Add min_count and max_count fields to request,
for creating multiple servers.

Closes rackspace/gophercloud#597
  • Loading branch information
stgleb committed Sep 26, 2016
1 parent c5d17b8 commit 0bc1b3d
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 0 deletions.
17 changes: 17 additions & 0 deletions openstack/compute/v2/servers/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,20 @@ type ErrServerNotFound struct {
func (e ErrServerNotFound) Error() string {
return fmt.Sprintf("I couldn't find server [%s]", e.ID)
}

type ErrMinGreaterThanMax struct {
Min int
Max int
}

func (err ErrMinGreaterThanMax) Error() string {
return fmt.Sprintf("Min %d is greater than Max %d", err.Min, err.Max)
}

type ErrNegativeValue struct {
Value int
}

func (err ErrNegativeValue) Error() string {
return fmt.Sprintf("Count cannot be negative %d", err.Value)
}
46 changes: 46 additions & 0 deletions openstack/compute/v2/servers/requests.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,48 @@ type CreateOpts struct {
// ServiceClient will allow calls to be made to retrieve an image or
// flavor ID by name.
ServiceClient *gophercloud.ServiceClient `json:"-"`

// Minimal count of servers to create
MinCount int `json:"_"`
// Maximal count of servers to be created
MaxCount int `json:"_"`
}

func setMinMaxCount(opts CreateOpts, request map[string]interface{}) error {
// Check count values are not negative
if opts.MinCount < 0 {
return ErrNegativeValue{
Value: opts.MinCount,
}
}

if opts.MaxCount < 0 {
return ErrNegativeValue{
Value: opts.MaxCount,
}
}

// Check min is less than max
if opts.MinCount > opts.MaxCount {
if opts.MinCount > opts.MaxCount {
err := ErrMinGreaterThanMax{
Min: opts.MinCount,
Max: opts.MaxCount,
}

return err
}
} else {
if opts.MinCount > 0 {
request["min_count"] = string(opts.MinCount)
}

if opts.MaxCount > 0 {
request["max_count"] = string(opts.MaxCount)
}
}

return nil
}

// ToServerCreateMap assembles a request body based on the contents of a CreateOpts.
Expand All @@ -189,6 +231,10 @@ func (opts CreateOpts) ToServerCreateMap() (map[string]interface{}, error) {
return nil, err
}

if err = setMinMaxCount(opts, b); err != nil {
return nil, err
}

if opts.UserData != nil {
encoded := base64.StdEncoding.EncodeToString(opts.UserData)
b["user_data"] = &encoded
Expand Down
47 changes: 47 additions & 0 deletions openstack/compute/v2/servers/testing/requests_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,53 @@ func TestCreateServerWithImageNameAndFlavorName(t *testing.T) {
th.CheckDeepEquals(t, ServerDerp, *actual)
}

func TestCreateMultipleServersPositive(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
HandleServerCreationSuccessfully(t, SingleServerBody)

actual, err := servers.Create(client.ServiceClient(), servers.CreateOpts{
Name: "derp",
ImageRef: "f90f6034-2570-4974-8351-6b49732ef2eb",
FlavorRef: "1",
MaxCount: 2,
}).Extract()
th.AssertNoErr(t, err)
th.CheckDeepEquals(t, ServerDerp, *actual)

actual, err = servers.Create(client.ServiceClient(), servers.CreateOpts{
Name: "derp",
ImageRef: "f90f6034-2570-4974-8351-6b49732ef2eb",
FlavorRef: "1",
MinCount: 2,
}).Extract()
th.AssertNoErr(t, err)
th.CheckDeepEquals(t, ServerDerp, *actual)
}

func TestCreateMultipleServersNegative(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
HandleServerCreationSuccessfully(t, SingleServerBody)

_, err := servers.Create(client.ServiceClient(), servers.CreateOpts{
Name: "derp",
ImageRef: "f90f6034-2570-4974-8351-6b49732ef2eb",
FlavorRef: "1",
MinCount: 2,
MaxCount: 1,
}).Extract()
th.AssertNotEquals(t, err, nil)

_, err = servers.Create(client.ServiceClient(), servers.CreateOpts{
Name: "derp",
ImageRef: "f90f6034-2570-4974-8351-6b49732ef2eb",
FlavorRef: "1",
MaxCount: -1,
}).Extract()
th.AssertNotEquals(t, err, nil)
}

func TestDeleteServer(t *testing.T) {
th.SetupHTTP()
defer th.TeardownHTTP()
Expand Down
7 changes: 7 additions & 0 deletions testhelper/convenience.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,13 @@ func CheckEquals(t *testing.T, expected, actual interface{}) {
}
}

// Useful to assert err != nil
func AssertNotEquals(t *testing.T, expected, actual interface{}) {
if expected != actual {
logError(t, fmt.Sprintf("expected %s but got %s", green(expected), yellow(actual)))
}
}

// AssertDeepEquals - like Equals - performs a comparison - but on more complex
// structures that requires deeper inspection
func AssertDeepEquals(t *testing.T, expected, actual interface{}) {
Expand Down

0 comments on commit 0bc1b3d

Please sign in to comment.