-
Notifications
You must be signed in to change notification settings - Fork 932
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add 'create-service-key' command in cli, story number #{87057732}
Add a new command named "create-service-key" to create a service key for a specified service instance. Signed-off-by: zhang-hua <zhuadl@cn.ibm.com>
- Loading branch information
Showing
20 changed files
with
773 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package fakes | ||
|
||
type FakeServiceKeyRepo struct { | ||
CreateServiceKeyError error | ||
|
||
CreateServiceKeyArgs CreateServiceKeyArgsType | ||
} | ||
|
||
type CreateServiceKeyArgsType struct { | ||
ServiceInstanceId string | ||
ServiceKeyName string | ||
} | ||
|
||
func NewFakeServiceKeyRepo() *FakeServiceKeyRepo { | ||
return &FakeServiceKeyRepo{ | ||
CreateServiceKeyArgs: CreateServiceKeyArgsType{}, | ||
} | ||
} | ||
|
||
func (f *FakeServiceKeyRepo) CreateServiceKey(instanceId string, serviceKeyName string) (apiErr error) { | ||
f.CreateServiceKeyArgs.ServiceInstanceId = instanceId | ||
f.CreateServiceKeyArgs.ServiceKeyName = serviceKeyName | ||
|
||
return f.CreateServiceKeyError | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package api | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
|
||
"github.com/cloudfoundry/cli/cf/configuration/core_config" | ||
"github.com/cloudfoundry/cli/cf/errors" | ||
"github.com/cloudfoundry/cli/cf/net" | ||
) | ||
|
||
type ServiceKeyRepository interface { | ||
CreateServiceKey(instanceId string, keyName string) (apiErr error) | ||
} | ||
|
||
type CloudControllerServiceKeyRepository struct { | ||
config core_config.Reader | ||
gateway net.Gateway | ||
} | ||
|
||
func NewCloudControllerServiceKeyRepository(config core_config.Reader, gateway net.Gateway) (repo CloudControllerServiceKeyRepository) { | ||
return CloudControllerServiceKeyRepository{ | ||
config: config, | ||
gateway: gateway, | ||
} | ||
} | ||
|
||
func (c CloudControllerServiceKeyRepository) CreateServiceKey(instanceId string, keyName string) (apiErr error) { | ||
path := "/v2/service_keys" | ||
data := fmt.Sprintf(`{"service_instance_guid":"%s","name":"%s"}`, instanceId, keyName) | ||
|
||
err := c.gateway.CreateResource(c.config.ApiEndpoint(), path, strings.NewReader(data)) | ||
|
||
if httpErr, ok := err.(errors.HttpError); ok && httpErr.ErrorCode() == errors.SERVICE_KEY_NAME_TAKEN { | ||
return errors.NewModelAlreadyExistsError("Service key", keyName) | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
package api_test | ||
|
||
import ( | ||
"net/http" | ||
"net/http/httptest" | ||
"time" | ||
|
||
testapi "github.com/cloudfoundry/cli/cf/api/fakes" | ||
testconfig "github.com/cloudfoundry/cli/testhelpers/configuration" | ||
testnet "github.com/cloudfoundry/cli/testhelpers/net" | ||
testterm "github.com/cloudfoundry/cli/testhelpers/terminal" | ||
|
||
"github.com/cloudfoundry/cli/cf/configuration/core_config" | ||
"github.com/cloudfoundry/cli/cf/errors" | ||
"github.com/cloudfoundry/cli/cf/net" | ||
|
||
. "github.com/cloudfoundry/cli/cf/api" | ||
. "github.com/cloudfoundry/cli/testhelpers/matchers" | ||
|
||
. "github.com/onsi/ginkgo" | ||
. "github.com/onsi/gomega" | ||
) | ||
|
||
var _ = Describe("Service Keys Repo", func() { | ||
var ( | ||
testServer *httptest.Server | ||
testHandler *testnet.TestHandler | ||
configRepo core_config.ReadWriter | ||
repo ServiceKeyRepository | ||
) | ||
|
||
setupTestServer := func(reqs ...testnet.TestRequest) { | ||
testServer, testHandler = testnet.NewServer(reqs) | ||
configRepo.SetApiEndpoint(testServer.URL) | ||
} | ||
|
||
BeforeEach(func() { | ||
configRepo = testconfig.NewRepositoryWithDefaults() | ||
configRepo.SetAccessToken("BEARER my_access_token") | ||
|
||
gateway := net.NewCloudControllerGateway(configRepo, time.Now, &testterm.FakeUI{}) | ||
repo = NewCloudControllerServiceKeyRepository(configRepo, gateway) | ||
}) | ||
|
||
Describe("creating a service key", func() { | ||
It("makes the right request", func() { | ||
setupTestServer(testapi.NewCloudControllerTestRequest(testnet.TestRequest{ | ||
Method: "POST", | ||
Path: "/v2/service_keys", | ||
Matcher: testnet.RequestBodyMatcher(`{"service_instance_guid": "fake-instance-guid", "name": "fake-key-name"}`), | ||
Response: testnet.TestResponse{Status: http.StatusCreated}, | ||
})) | ||
|
||
err := repo.CreateServiceKey("fake-instance-guid", "fake-key-name") | ||
Expect(testHandler).To(HaveAllRequestsCalled()) | ||
Expect(err).NotTo(HaveOccurred()) | ||
}) | ||
|
||
It("returns a ModelAlreadyExistsError if the service key exists", func() { | ||
setupTestServer(testapi.NewCloudControllerTestRequest(testnet.TestRequest{ | ||
Method: "POST", | ||
Path: "/v2/service_keys", | ||
Matcher: testnet.RequestBodyMatcher(`{"service_instance_guid":"fake-instance-guid","name":"exist-service-key"}`), | ||
Response: testnet.TestResponse{ | ||
Status: http.StatusBadRequest, | ||
Body: `{"code":60003,"description":"The service key name is taken: exist-service-key"}`}, | ||
})) | ||
|
||
err := repo.CreateServiceKey("fake-instance-guid", "exist-service-key") | ||
Expect(testHandler).To(HaveAllRequestsCalled()) | ||
Expect(err).To(BeAssignableToTypeOf(&errors.ModelAlreadyExistsError{})) | ||
}) | ||
}) | ||
|
||
AfterEach(func() { | ||
testServer.Close() | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
package servicekey | ||
|
||
import ( | ||
"github.com/cloudfoundry/cli/cf/api" | ||
"github.com/cloudfoundry/cli/cf/command_metadata" | ||
"github.com/cloudfoundry/cli/cf/configuration/core_config" | ||
"github.com/cloudfoundry/cli/cf/errors" | ||
"github.com/cloudfoundry/cli/cf/requirements" | ||
"github.com/cloudfoundry/cli/cf/terminal" | ||
"github.com/codegangsta/cli" | ||
|
||
. "github.com/cloudfoundry/cli/cf/i18n" | ||
) | ||
|
||
type CreateServiceKey struct { | ||
ui terminal.UI | ||
config core_config.Reader | ||
serviceRepo api.ServiceRepository | ||
serviceKeyRepo api.ServiceKeyRepository | ||
} | ||
|
||
func NewCreateServiceKey(ui terminal.UI, config core_config.Reader, serviceRepo api.ServiceRepository, serviceKeyRepo api.ServiceKeyRepository) (cmd CreateServiceKey) { | ||
return CreateServiceKey{ | ||
ui: ui, | ||
config: config, | ||
serviceRepo: serviceRepo, | ||
serviceKeyRepo: serviceKeyRepo, | ||
} | ||
} | ||
|
||
func (cmd CreateServiceKey) Metadata() command_metadata.CommandMetadata { | ||
return command_metadata.CommandMetadata{ | ||
Name: "create-service-key", | ||
ShortName: "csk", | ||
Description: T("Create key for a service instance"), | ||
Usage: T(`CF_NAME create-service-key SERVICE_INSTANCE SERVICE_KEY | ||
EXAMPLE: | ||
CF_NAME create-service-key mydb mykey`), | ||
} | ||
} | ||
|
||
func (cmd CreateServiceKey) GetRequirements(requirementsFactory requirements.Factory, c *cli.Context) (reqs []requirements.Requirement, err error) { | ||
if len(c.Args()) != 2 { | ||
cmd.ui.FailWithUsage(c) | ||
} | ||
|
||
loginRequirement := requirementsFactory.NewLoginRequirement() | ||
serviceInstanceRequirement := requirementsFactory.NewServiceInstanceRequirement(c.Args()[0]) | ||
targetSpaceRequirement := requirementsFactory.NewTargetedSpaceRequirement() | ||
|
||
reqs = []requirements.Requirement{loginRequirement, serviceInstanceRequirement, targetSpaceRequirement} | ||
|
||
return reqs, nil | ||
} | ||
|
||
func (cmd CreateServiceKey) Run(c *cli.Context) { | ||
serviceInstanceName := c.Args()[0] | ||
serviceKeyName := c.Args()[1] | ||
|
||
cmd.ui.Say(T("Creating service key {{.ServiceKeyName}} for service instance {{.ServiceInstanceName}} as {{.CurrentUser}}...", | ||
map[string]interface{}{ | ||
"ServiceInstanceName": terminal.EntityNameColor(serviceInstanceName), | ||
"ServiceKeyName": terminal.EntityNameColor(serviceKeyName), | ||
"CurrentUser": terminal.EntityNameColor(cmd.config.Username()), | ||
})) | ||
|
||
serviceInstance, err := cmd.serviceRepo.FindInstanceByName(serviceInstanceName) | ||
if err != nil { | ||
cmd.ui.Failed(err.Error()) | ||
return | ||
} | ||
|
||
err = cmd.serviceKeyRepo.CreateServiceKey(serviceInstance.Guid, serviceKeyName) | ||
if err != nil { | ||
cmd.ui.Failed(err.Error()) | ||
return | ||
} | ||
|
||
switch err.(type) { | ||
case nil: | ||
cmd.ui.Ok() | ||
case *errors.ModelAlreadyExistsError: | ||
cmd.ui.Ok() | ||
cmd.ui.Warn(err.Error()) | ||
default: | ||
cmd.ui.Failed(err.Error()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
package servicekey_test | ||
|
||
import ( | ||
"github.com/cloudfoundry/cli/cf/configuration/core_config" | ||
"github.com/cloudfoundry/cli/cf/errors" | ||
"github.com/cloudfoundry/cli/cf/models" | ||
"github.com/cloudfoundry/cli/generic" | ||
|
||
testapi "github.com/cloudfoundry/cli/cf/api/fakes" | ||
testcmd "github.com/cloudfoundry/cli/testhelpers/commands" | ||
testconfig "github.com/cloudfoundry/cli/testhelpers/configuration" | ||
testreq "github.com/cloudfoundry/cli/testhelpers/requirements" | ||
testterm "github.com/cloudfoundry/cli/testhelpers/terminal" | ||
|
||
. "github.com/cloudfoundry/cli/cf/commands/servicekey" | ||
. "github.com/cloudfoundry/cli/testhelpers/matchers" | ||
|
||
. "github.com/onsi/ginkgo" | ||
. "github.com/onsi/gomega" | ||
) | ||
|
||
var _ = Describe("create-service-key command", func() { | ||
var ( | ||
ui *testterm.FakeUI | ||
config core_config.Repository | ||
cmd CreateServiceKey | ||
requirementsFactory *testreq.FakeReqFactory | ||
serviceRepo *testapi.FakeServiceRepo | ||
serviceKeyRepo *testapi.FakeServiceKeyRepo | ||
) | ||
|
||
BeforeEach(func() { | ||
ui = &testterm.FakeUI{} | ||
config = testconfig.NewRepositoryWithDefaults() | ||
serviceRepo = &testapi.FakeServiceRepo{} | ||
serviceInstance := models.ServiceInstance{} | ||
serviceInstance.Guid = "fake-instance-guid" | ||
serviceRepo.FindInstanceByNameMap = generic.NewMap() | ||
serviceRepo.FindInstanceByNameMap.Set("fake-service-instance", serviceInstance) | ||
serviceKeyRepo = testapi.NewFakeServiceKeyRepo() | ||
cmd = NewCreateServiceKey(ui, config, serviceRepo, serviceKeyRepo) | ||
requirementsFactory = &testreq.FakeReqFactory{LoginSuccess: true, TargetedSpaceSuccess: true, ServiceInstanceNotFound: false} | ||
}) | ||
|
||
var callCreateService = func(args []string) bool { | ||
return testcmd.RunCommand(cmd, args, requirementsFactory) | ||
} | ||
|
||
Describe("requirements", func() { | ||
It("fails when not logged in", func() { | ||
requirementsFactory = &testreq.FakeReqFactory{LoginSuccess: false} | ||
Expect(callCreateService([]string{"fake-service-instance", "fake-service-key"})).To(BeFalse()) | ||
}) | ||
|
||
It("requires two arguments to run", func() { | ||
Expect(callCreateService([]string{})).To(BeFalse()) | ||
Expect(callCreateService([]string{"fake-arg-one"})).To(BeFalse()) | ||
Expect(callCreateService([]string{"fake-arg-one", "fake-arg-two", "fake-arg-three"})).To(BeFalse()) | ||
}) | ||
|
||
It("fails when service instance is not found", func() { | ||
requirementsFactory = &testreq.FakeReqFactory{LoginSuccess: true, ServiceInstanceNotFound: true} | ||
Expect(callCreateService([]string{"non-exist-service-instance", "fake-service-key"})).To(BeFalse()) | ||
}) | ||
|
||
It("fails when space is not targetted", func() { | ||
requirementsFactory = &testreq.FakeReqFactory{LoginSuccess: true, TargetedSpaceSuccess: false} | ||
Expect(callCreateService([]string{"non-exist-service-instance", "fake-service-key"})).To(BeFalse()) | ||
}) | ||
}) | ||
|
||
Describe("requiremnts are satisfied", func() { | ||
It("create service key successfully", func() { | ||
callCreateService([]string{"fake-service-instance", "fake-service-key"}) | ||
|
||
Expect(ui.Outputs).To(ContainSubstrings( | ||
[]string{"Creating service key", "fake-service-key", "for service instance", "fake-service-instance", "as", "my-user"}, | ||
[]string{"OK"}, | ||
)) | ||
Expect(serviceKeyRepo.CreateServiceKeyArgs.ServiceInstanceId).To(Equal("fake-instance-guid")) | ||
Expect(serviceKeyRepo.CreateServiceKeyArgs.ServiceKeyName).To(Equal("fake-service-key")) | ||
}) | ||
|
||
It("create service key failed when the service key already exists", func() { | ||
serviceKeyRepo.CreateServiceKeyError = errors.NewModelAlreadyExistsError("ServiceKey", "exist-service-key") | ||
callCreateService([]string{"fake-service-instance", "exist-service-key"}) | ||
|
||
Expect(ui.Outputs).To(ContainSubstrings( | ||
[]string{"Creating service key", "exist-service-key", "for service instance", "fake-service-instance", "as", "my-user"}, | ||
[]string{"FAILED"}, | ||
[]string{"ServiceKey exist-service-key already exists"})) | ||
}) | ||
}) | ||
}) |
Oops, something went wrong.