diff --git a/cmd/svcat/broker/register_cmd.go b/cmd/svcat/broker/register_cmd.go index 79f198ae340..e2292c7516a 100644 --- a/cmd/svcat/broker/register_cmd.go +++ b/cmd/svcat/broker/register_cmd.go @@ -18,23 +18,43 @@ package broker import ( "fmt" + "os" + "strings" + "time" "github.com/kubernetes-incubator/service-catalog/cmd/svcat/command" "github.com/kubernetes-incubator/service-catalog/cmd/svcat/output" + "github.com/kubernetes-incubator/service-catalog/pkg/apis/servicecatalog/v1beta1" + servicecatalog "github.com/kubernetes-incubator/service-catalog/pkg/svcat/service-catalog" "github.com/spf13/cobra" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // RegisterCmd contains the information needed to register a broker type RegisterCmd struct { - BrokerName string - Context *command.Context - URL string + *command.Namespaced + *command.Waitable + + Context *command.Context + + BasicSecret string + BearerSecret string + BrokerName string + CAFile string + ClassRestrictions []string + PlanRestrictions []string + SkipTLS bool + RelistBehavior string + RelistDuration time.Duration + URL string } // NewRegisterCmd builds a "svcat register" command func NewRegisterCmd(cxt *command.Context) *cobra.Command { registerCmd := &RegisterCmd{ - Context: cxt, + Context: cxt, + Namespaced: command.NewNamespaced(cxt), + Waitable: command.NewWaitable(), } cmd := &cobra.Command{ Use: "register NAME --url URL", @@ -48,27 +68,73 @@ func NewRegisterCmd(cxt *command.Context) *cobra.Command { cmd.Flags().StringVar(®isterCmd.URL, "url", "", "The broker URL (Required)") cmd.MarkFlagRequired("url") + cmd.Flags().StringVar(®isterCmd.BasicSecret, "basic-secret", "", + "A secret containing basic auth (username/password) information to connect to the broker") + cmd.Flags().StringVar(®isterCmd.BearerSecret, "bearer-secret", "", + "A secret containing a bearer token to connect to the broker") + cmd.Flags().StringVar(®isterCmd.CAFile, "ca", "", + "A file containing the CA certificate to connect to the broker") + cmd.Flags().StringSliceVar(®isterCmd.ClassRestrictions, "class-restrictions", []string{}, + "A list of restrictions to apply to the classes allowed from the broker") + cmd.Flags().StringSliceVar(®isterCmd.PlanRestrictions, "plan-restrictions", []string{}, + "A list of restrictions to apply to the plans allowed from the broker") + cmd.Flags().StringVar(®isterCmd.RelistBehavior, "relist-behavior", "", + "Behavior for relisting the broker's catalog. Valid options are manual or duration. Defaults to duration with an interval of 15m.") + cmd.Flags().DurationVar(®isterCmd.RelistDuration, "relist-duration", 0*time.Second, + "Interval to refetch broker catalog when relist-behavior is set to duration, specified in human readable format: 30s, 1m, 1h") + cmd.Flags().BoolVar(®isterCmd.SkipTLS, "skip-tls", false, + "Disables TLS certificate verification when communicating with this broker. This is strongly discouraged. You should use --ca instead.") + registerCmd.AddNamespaceFlags(cmd.Flags(), false) + registerCmd.AddWaitFlags(cmd) + return cmd } // Validate checks that the required arguements have been provided func (c *RegisterCmd) Validate(args []string) error { - if len(args) == 0 { + if len(args) < 1 { return fmt.Errorf("a broker name is required") } c.BrokerName = args[0] + if c.BasicSecret != "" && c.BearerSecret != "" { + return fmt.Errorf("cannot use both basic auth and bearer auth") + } + + if c.CAFile != "" { + _, err := os.Stat(c.CAFile) + if err != nil { + return fmt.Errorf("error finding CA file: %v", err.Error()) + } + } + if c.RelistBehavior != "" { + c.RelistBehavior = strings.ToLower(c.RelistBehavior) + if c.RelistBehavior != "duration" && c.RelistBehavior != "manual" { + return fmt.Errorf("invalid --relist-duration value, allowed values are: duration, manual") + } + } return nil } -// Run runs the command +// Run creates the broker and then displays the broker details func (c *RegisterCmd) Run() error { - return c.Register() -} + opts := &servicecatalog.RegisterOptions{ + BasicSecret: c.BasicSecret, + BearerSecret: c.BearerSecret, + CAFile: c.CAFile, + ClassRestrictions: c.ClassRestrictions, + Namespace: c.Namespace, + PlanRestrictions: c.PlanRestrictions, + SkipTLS: c.SkipTLS, + } + if c.RelistBehavior == "duration" { + opts.RelistBehavior = v1beta1.ServiceBrokerRelistBehaviorDuration + opts.RelistDuration = &metav1.Duration{Duration: c.RelistDuration} + } else if c.RelistBehavior == "manual" { + opts.RelistBehavior = v1beta1.ServiceBrokerRelistBehaviorManual + } -// Register calls out to the pkg lib to create the broker and displays the output -func (c *RegisterCmd) Register() error { - broker, err := c.Context.App.Register(c.BrokerName, c.URL) + broker, err := c.Context.App.Register(c.BrokerName, c.URL, opts) if err != nil { return err } diff --git a/cmd/svcat/broker/register_cmd_test.go b/cmd/svcat/broker/register_cmd_test.go index f74cddd0a95..49d23510724 100644 --- a/cmd/svcat/broker/register_cmd_test.go +++ b/cmd/svcat/broker/register_cmd_test.go @@ -18,21 +18,25 @@ package broker_test import ( "bytes" + "time" . "github.com/kubernetes-incubator/service-catalog/cmd/svcat/broker" "github.com/kubernetes-incubator/service-catalog/cmd/svcat/command" "github.com/kubernetes-incubator/service-catalog/cmd/svcat/test" "github.com/kubernetes-incubator/service-catalog/pkg/apis/servicecatalog/v1beta1" "github.com/kubernetes-incubator/service-catalog/pkg/svcat" + servicecatalog "github.com/kubernetes-incubator/service-catalog/pkg/svcat/service-catalog" "github.com/kubernetes-incubator/service-catalog/pkg/svcat/service-catalog/service-catalogfakes" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + "github.com/spf13/pflag" "k8s.io/apimachinery/pkg/apis/meta/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) var _ = Describe("Register Command", func() { Describe("NewRegisterCmd", func() { - It("Builds and returns a cobra command", func() { + It("Builds and returns a cobra command with the correct flags", func() { cxt := &command.Context{} cmd := NewRegisterCmd(cxt) Expect(*cmd).NotTo(BeNil()) @@ -40,23 +44,196 @@ var _ = Describe("Register Command", func() { Expect(cmd.Short).To(ContainSubstring("Registers a new broker with service catalog")) Expect(cmd.Example).To(ContainSubstring("svcat register mysqlbroker --url http://mysqlbroker.com")) Expect(len(cmd.Aliases)).To(Equal(0)) + + urlFlag := cmd.Flags().Lookup("url") + Expect(urlFlag).NotTo(BeNil()) + Expect(urlFlag.Usage).To(ContainSubstring("The broker URL (Required)")) + + basicSecretFlag := cmd.Flags().Lookup("basic-secret") + Expect(basicSecretFlag).NotTo(BeNil()) + Expect(basicSecretFlag.Usage).To(ContainSubstring("A secret containing basic auth (username/password) information to connect to the broker")) + + bearerSecretFlag := cmd.Flags().Lookup("bearer-secret") + Expect(bearerSecretFlag).NotTo(BeNil()) + Expect(bearerSecretFlag.Usage).To(ContainSubstring("A secret containing a bearer token to connect to the broker")) + + caFlag := cmd.Flags().Lookup("ca") + Expect(caFlag).NotTo(BeNil()) + Expect(caFlag.Usage).To(ContainSubstring("A file containing the CA certificate to connect to the broker")) + + classRestrictionFlag := cmd.Flags().Lookup("class-restrictions") + Expect(classRestrictionFlag).NotTo(BeNil()) + Expect(classRestrictionFlag.Usage).To(ContainSubstring("A list of restrictions to apply to the classes allowed from the broker")) + + planRestrictionFlag := cmd.Flags().Lookup("plan-restrictions") + Expect(planRestrictionFlag).NotTo(BeNil()) + Expect(planRestrictionFlag.Usage).To(ContainSubstring("A list of restrictions to apply to the plans allowed from the broker")) + + relistBehaviorFlag := cmd.Flags().Lookup("relist-behavior") + Expect(relistBehaviorFlag).NotTo(BeNil()) + Expect(relistBehaviorFlag.Usage).To(ContainSubstring("Behavior for relisting the broker's catalog. Valid options are manual or duration. Defaults to duration with an interval of 15m.")) + + relistDurationFlag := cmd.Flags().Lookup("relist-duration") + Expect(relistDurationFlag).NotTo(BeNil()) + Expect(relistDurationFlag.Usage).To(ContainSubstring("Interval to refetch broker catalog when relist-behavior is set to duration, specified in human readable format: 30s, 1m, 1h")) + + skipTLSFlag := cmd.Flags().Lookup("skip-tls") + Expect(skipTLSFlag).NotTo(BeNil()) + Expect(skipTLSFlag.Usage).To(ContainSubstring("Disables TLS certificate verification when communicating with this broker. This is strongly discouraged. You should use --ca instead.")) + + waitFlag := cmd.Flags().Lookup("wait") + Expect(waitFlag).NotTo(BeNil()) + timeoutFlag := cmd.Flags().Lookup("timeout") + Expect(timeoutFlag).NotTo(BeNil()) + intervalFlag := cmd.Flags().Lookup("interval") + Expect(intervalFlag).NotTo(BeNil()) }) }) + Describe("Validate", func() { + It("succeeds if a broker name and url are provided", func() { + cmd := RegisterCmd{} + err := cmd.Validate([]string{"bananabroker", "http://bananabroker.com"}) + Expect(err).NotTo(HaveOccurred()) + }) It("errors if a broker name is not provided", func() { + cmd := RegisterCmd{} + err := cmd.Validate([]string{}) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("a broker name is required")) + }) + It("errors if both basic-secret and bearer-secret are provided", func() { + basicSecret := "basicsecret" + bearerSecret := "bearersecret" cmd := RegisterCmd{ - BrokerName: "", - Context: nil, - URL: "http://bananabroker.com", + BasicSecret: basicSecret, + BearerSecret: bearerSecret, } - err := cmd.Validate([]string{}) + err := cmd.Validate([]string{"bananabroker", "http://bananabroker.com", "--basic-secret", basicSecret, "--bearer-secret", bearerSecret}) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("cannot use both basic auth and bearer auth")) + }) + It("errors if a provided CA file does not exist", func() { + cmd := RegisterCmd{ + CAFile: "/not/a/real/file", + } + err := cmd.Validate([]string{"bananabroker", "http://bananabroker.com"}) + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("error finding CA file")) + }) + It("only allows valid values for relist behavior", func() { + cmd := RegisterCmd{ + RelistBehavior: "foobar", + } + err := cmd.Validate([]string{"bananabroker", "http://bananabroker.com"}) Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("invalid --relist-duration value, allowed values are: duration, manual")) + + cmd = RegisterCmd{ + RelistBehavior: "Duration", + } + err = cmd.Validate([]string{"bananabroker", "http://bananabroker.com"}) + Expect(err).NotTo(HaveOccurred()) + + cmd = RegisterCmd{ + RelistBehavior: "MANUAL", + } + err = cmd.Validate([]string{"bananabroker", "http://bananabroker.com"}) + Expect(err).NotTo(HaveOccurred()) }) }) - Describe("Register", func() { + Describe("Run", func() { It("Calls the pkg/svcat libs Register method with the passed in variables and prints output to the user", func() { brokerName := "foobarbroker" brokerURL := "http://foobar.com" + basicSecret := "foobarsecret" + certFile := "register_cmd_test.go" + certFileContents := []byte("foobarCA") + classRestrictions := []string{"foobarclassa", "foobarclassb"} + namespace := "foobarnamespace" + planRestrictions := []string{"foobarplana", "foobarplanb"} + skipTLS := true + relistBehavior := "duration" + relistBehaviorConst := v1beta1.ServiceBrokerRelistBehaviorDuration + relistDuration := 10 * time.Minute + metaRelistDuration := &metav1.Duration{Duration: relistDuration} + + brokerToReturn := &v1beta1.ClusterServiceBroker{ + ObjectMeta: v1.ObjectMeta{ + Name: brokerName, + }, + Spec: v1beta1.ClusterServiceBrokerSpec{ + CommonServiceBrokerSpec: v1beta1.CommonServiceBrokerSpec{ + CABundle: certFileContents, + InsecureSkipTLSVerify: skipTLS, + RelistBehavior: relistBehaviorConst, + RelistDuration: metaRelistDuration, + URL: brokerURL, + CatalogRestrictions: &v1beta1.CatalogRestrictions{ + ServiceClass: classRestrictions, + ServicePlan: planRestrictions, + }, + }, + AuthInfo: &v1beta1.ClusterServiceBrokerAuthInfo{ + Basic: &v1beta1.ClusterBasicAuthConfig{ + SecretRef: &v1beta1.ObjectReference{ + Name: basicSecret, + Namespace: namespace, + }, + }, + }, + }, + } + + outputBuffer := &bytes.Buffer{} + + fakeApp, _ := svcat.NewApp(nil, nil, namespace) + fakeSDK := new(servicecatalogfakes.FakeSvcatClient) + fakeSDK.RegisterReturns(brokerToReturn, nil) + fakeApp.SvcatClient = fakeSDK + cxt := svcattest.NewContext(outputBuffer, fakeApp) + cmd := RegisterCmd{ + Context: cxt, + BasicSecret: basicSecret, + BrokerName: brokerName, + CAFile: certFile, + ClassRestrictions: classRestrictions, + Namespaced: command.NewNamespaced(cxt), + PlanRestrictions: planRestrictions, + RelistBehavior: relistBehavior, + RelistDuration: relistDuration, + SkipTLS: skipTLS, + URL: brokerURL, + } + cmd.Namespaced.ApplyNamespaceFlags(&pflag.FlagSet{}) + err := cmd.Run() + + Expect(err).NotTo(HaveOccurred()) + Expect(fakeSDK.RegisterCallCount()).To(Equal(1)) + returnedName, returnedURL, returnedOpts := fakeSDK.RegisterArgsForCall(0) + Expect(returnedName).To(Equal(brokerName)) + Expect(returnedURL).To(Equal(brokerURL)) + opts := servicecatalog.RegisterOptions{ + BasicSecret: basicSecret, + CAFile: certFile, + ClassRestrictions: classRestrictions, + Namespace: namespace, + PlanRestrictions: planRestrictions, + RelistBehavior: relistBehaviorConst, + RelistDuration: metaRelistDuration, + SkipTLS: skipTLS, + } + Expect(*returnedOpts).To(Equal(opts)) + + output := outputBuffer.String() + Expect(output).To(ContainSubstring(brokerName)) + Expect(output).To(ContainSubstring(brokerURL)) + }) + It("Passes in the bearer secret", func() { + brokerName := "foobarbroker" + brokerURL := "http://foobar.com" + bearerSecret := "foobarsecret" + namespace := "foobarnamespace" brokerToReturn := &v1beta1.ClusterServiceBroker{ ObjectMeta: v1.ObjectMeta{ @@ -66,26 +243,43 @@ var _ = Describe("Register Command", func() { CommonServiceBrokerSpec: v1beta1.CommonServiceBrokerSpec{ URL: brokerURL, }, + AuthInfo: &v1beta1.ClusterServiceBrokerAuthInfo{ + Basic: &v1beta1.ClusterBasicAuthConfig{ + SecretRef: &v1beta1.ObjectReference{ + Name: bearerSecret, + }, + }, + }, }, } outputBuffer := &bytes.Buffer{} - fakeApp, _ := svcat.NewApp(nil, nil, "default") + fakeApp, _ := svcat.NewApp(nil, nil, namespace) fakeSDK := new(servicecatalogfakes.FakeSvcatClient) fakeSDK.RegisterReturns(brokerToReturn, nil) fakeApp.SvcatClient = fakeSDK + cxt := svcattest.NewContext(outputBuffer, fakeApp) cmd := RegisterCmd{ - Context: svcattest.NewContext(outputBuffer, fakeApp), - BrokerName: brokerName, - URL: brokerURL, + Context: cxt, + BearerSecret: bearerSecret, + BrokerName: brokerName, + Namespaced: command.NewNamespaced(cxt), + URL: brokerURL, } - err := cmd.Register() + cmd.Namespaced.ApplyNamespaceFlags(&pflag.FlagSet{}) + err := cmd.Run() Expect(err).NotTo(HaveOccurred()) - returnedName, returnedURL := fakeSDK.RegisterArgsForCall(0) + Expect(fakeSDK.RegisterCallCount()).To(Equal(1)) + returnedName, returnedURL, returnedOpts := fakeSDK.RegisterArgsForCall(0) Expect(returnedName).To(Equal(brokerName)) Expect(returnedURL).To(Equal(brokerURL)) + opts := servicecatalog.RegisterOptions{ + Namespace: namespace, + BearerSecret: bearerSecret, + } + Expect(*returnedOpts).To(Equal(opts)) output := outputBuffer.String() Expect(output).To(ContainSubstring(brokerName)) diff --git a/cmd/svcat/testdata/output/completion-bash.txt b/cmd/svcat/testdata/output/completion-bash.txt index dedda5349bf..5a5505f97fd 100644 --- a/cmd/svcat/testdata/output/completion-bash.txt +++ b/cmd/svcat/testdata/output/completion-bash.txt @@ -781,8 +781,33 @@ _svcat_register() flags_with_completion=() flags_completion=() + flags+=("--basic-secret=") + local_nonpersistent_flags+=("--basic-secret=") + flags+=("--bearer-secret=") + local_nonpersistent_flags+=("--bearer-secret=") + flags+=("--ca=") + local_nonpersistent_flags+=("--ca=") + flags+=("--class-restrictions=") + local_nonpersistent_flags+=("--class-restrictions=") + flags+=("--interval=") + local_nonpersistent_flags+=("--interval=") + flags+=("--namespace=") + two_word_flags+=("-n") + local_nonpersistent_flags+=("--namespace=") + flags+=("--plan-restrictions=") + local_nonpersistent_flags+=("--plan-restrictions=") + flags+=("--relist-behavior=") + local_nonpersistent_flags+=("--relist-behavior=") + flags+=("--relist-duration=") + local_nonpersistent_flags+=("--relist-duration=") + flags+=("--skip-tls") + local_nonpersistent_flags+=("--skip-tls") + flags+=("--timeout=") + local_nonpersistent_flags+=("--timeout=") flags+=("--url=") local_nonpersistent_flags+=("--url=") + flags+=("--wait") + local_nonpersistent_flags+=("--wait") flags+=("--context=") flags+=("--kubeconfig=") flags+=("--logtostderr") diff --git a/cmd/svcat/testdata/output/completion-zsh.txt b/cmd/svcat/testdata/output/completion-zsh.txt index 05e87d1800b..987cd06249b 100644 --- a/cmd/svcat/testdata/output/completion-zsh.txt +++ b/cmd/svcat/testdata/output/completion-zsh.txt @@ -915,8 +915,33 @@ _svcat_register() flags_with_completion=() flags_completion=() + flags+=("--basic-secret=") + local_nonpersistent_flags+=("--basic-secret=") + flags+=("--bearer-secret=") + local_nonpersistent_flags+=("--bearer-secret=") + flags+=("--ca=") + local_nonpersistent_flags+=("--ca=") + flags+=("--class-restrictions=") + local_nonpersistent_flags+=("--class-restrictions=") + flags+=("--interval=") + local_nonpersistent_flags+=("--interval=") + flags+=("--namespace=") + two_word_flags+=("-n") + local_nonpersistent_flags+=("--namespace=") + flags+=("--plan-restrictions=") + local_nonpersistent_flags+=("--plan-restrictions=") + flags+=("--relist-behavior=") + local_nonpersistent_flags+=("--relist-behavior=") + flags+=("--relist-duration=") + local_nonpersistent_flags+=("--relist-duration=") + flags+=("--skip-tls") + local_nonpersistent_flags+=("--skip-tls") + flags+=("--timeout=") + local_nonpersistent_flags+=("--timeout=") flags+=("--url=") local_nonpersistent_flags+=("--url=") + flags+=("--wait") + local_nonpersistent_flags+=("--wait") flags+=("--context=") flags+=("--kubeconfig=") flags+=("--logtostderr") diff --git a/cmd/svcat/testdata/plugin.yaml b/cmd/svcat/testdata/plugin.yaml index bf58839ad35..921a5b6d2ef 100644 --- a/cmd/svcat/testdata/plugin.yaml +++ b/cmd/svcat/testdata/plugin.yaml @@ -277,8 +277,36 @@ tree: example: ' svcat register mysqlbroker --url http://mysqlbroker.com' command: ./svcat register flags: + - name: basic-secret + desc: A secret containing basic auth (username/password) information to connect + to the broker + - name: bearer-secret + desc: A secret containing a bearer token to connect to the broker + - name: ca + desc: A file containing the CA certificate to connect to the broker + - name: class-restrictions + desc: A list of restrictions to apply to the classes allowed from the broker + - name: interval + desc: 'Poll interval for --wait, specified in human readable format: 30s, 1m, + 1h' + - name: plan-restrictions + desc: A list of restrictions to apply to the plans allowed from the broker + - name: relist-behavior + desc: Behavior for relisting the broker's catalog. Valid options are manual or + duration. Defaults to duration with an interval of 15m. + - name: relist-duration + desc: 'Interval to refetch broker catalog when relist-behavior is set to duration, + specified in human readable format: 30s, 1m, 1h' + - name: skip-tls + desc: Disables TLS certificate verification when communicating with this broker. + This is strongly discouraged. You should use --ca instead. + - name: timeout + desc: 'Timeout for --wait, specified in human readable format: 30s, 1m, 1h. Specify + -1 to wait indefinitely.' - name: url desc: The broker URL (Required) + - name: wait + desc: Wait until the operation completes. - name: sync use: sync shortDesc: Syncs service catalog for a service broker diff --git a/pkg/svcat/service-catalog/assets/ca b/pkg/svcat/service-catalog/assets/ca new file mode 100644 index 00000000000..257cc5642cb --- /dev/null +++ b/pkg/svcat/service-catalog/assets/ca @@ -0,0 +1 @@ +foo diff --git a/pkg/svcat/service-catalog/broker.go b/pkg/svcat/service-catalog/broker.go index 85435324c73..a9fd0c54a4e 100644 --- a/pkg/svcat/service-catalog/broker.go +++ b/pkg/svcat/service-catalog/broker.go @@ -18,6 +18,7 @@ package servicecatalog import ( "fmt" + "io/ioutil" "github.com/kubernetes-incubator/service-catalog/pkg/apis/servicecatalog/v1beta1" "k8s.io/apimachinery/pkg/api/errors" @@ -65,18 +66,55 @@ func (sdk *SDK) RetrieveBrokerByClass(class *v1beta1.ClusterServiceClass, return broker, nil } -// Register creates a broker -func (sdk *SDK) Register(brokerName string, url string) (*v1beta1.ClusterServiceBroker, error) { +//Register creates a broker +func (sdk *SDK) Register(brokerName string, url string, opts *RegisterOptions) (*v1beta1.ClusterServiceBroker, error) { + var err error + var caBytes []byte + if opts.CAFile != "" { + caBytes, err = ioutil.ReadFile(opts.CAFile) + if err != nil { + return nil, fmt.Errorf("Error opening CA file: %v", err.Error()) + } + + } request := &v1beta1.ClusterServiceBroker{ ObjectMeta: v1.ObjectMeta{ Name: brokerName, }, Spec: v1beta1.ClusterServiceBrokerSpec{ CommonServiceBrokerSpec: v1beta1.CommonServiceBrokerSpec{ - URL: url, + CABundle: caBytes, + InsecureSkipTLSVerify: opts.SkipTLS, + RelistBehavior: opts.RelistBehavior, + RelistDuration: opts.RelistDuration, + URL: url, + CatalogRestrictions: &v1beta1.CatalogRestrictions{ + ServiceClass: opts.ClassRestrictions, + ServicePlan: opts.PlanRestrictions, + }, }, }, } + if opts.BasicSecret != "" { + request.Spec.AuthInfo = &v1beta1.ClusterServiceBrokerAuthInfo{ + Basic: &v1beta1.ClusterBasicAuthConfig{ + SecretRef: &v1beta1.ObjectReference{ + Name: opts.BasicSecret, + Namespace: opts.Namespace, + }, + }, + } + } else if opts.BearerSecret != "" { + request.Spec.AuthInfo = &v1beta1.ClusterServiceBrokerAuthInfo{ + Bearer: &v1beta1.ClusterBearerTokenAuthConfig{ + SecretRef: &v1beta1.ObjectReference{ + Name: opts.BearerSecret, + Namespace: opts.Namespace, + }, + }, + } + } + result, err := sdk.ServiceCatalog().ClusterServiceBrokers().Create(request) if err != nil { return nil, fmt.Errorf("register request failed (%s)", err) diff --git a/pkg/svcat/service-catalog/broker_test.go b/pkg/svcat/service-catalog/broker_test.go index 1b51f1d129a..321b70e2572 100644 --- a/pkg/svcat/service-catalog/broker_test.go +++ b/pkg/svcat/service-catalog/broker_test.go @@ -18,6 +18,7 @@ package servicecatalog_test import ( "fmt" + "time" "github.com/kubernetes-incubator/service-catalog/pkg/apis/servicecatalog/v1beta1" "github.com/kubernetes-incubator/service-catalog/pkg/client/clientset_generated/clientset/fake" @@ -149,8 +150,58 @@ var _ = Describe("Broker", func() { It("creates a broker by calling the v1beta1 Create method with the passed in arguements", func() { brokerName := "potato_broker" url := "http://potato.com" + basicSecret := "potatobasicsecret" + caFile := "assets/ca" + namespace := "potatonamespace" + planRestrictions := []string{"potatoplana", "potatoplanb"} + relistBehavior := v1beta1.ServiceBrokerRelistBehaviorDuration + relistDuration := &metav1.Duration{Duration: 10 * time.Minute} + skipTLS := true + + opts := &RegisterOptions{ + BasicSecret: basicSecret, + CAFile: caFile, + Namespace: namespace, + PlanRestrictions: planRestrictions, + RelistBehavior: relistBehavior, + RelistDuration: relistDuration, + SkipTLS: skipTLS, + } + broker, err := sdk.Register(brokerName, url, opts) - broker, err := sdk.Register(brokerName, url) + Expect(err).NotTo(HaveOccurred()) + Expect(broker).NotTo(BeNil()) + Expect(broker.Name).To(Equal(brokerName)) + Expect(broker.Spec.URL).To(Equal(url)) + Expect(broker.Spec.CABundle).To(Equal([]byte("foo\n"))) + Expect(broker.Spec.InsecureSkipTLSVerify).To(BeTrue()) + Expect(broker.Spec.RelistBehavior).To(Equal(relistBehavior)) + Expect(broker.Spec.RelistDuration).To(Equal(relistDuration)) + Expect(broker.Spec.CatalogRestrictions.ServicePlan).To(Equal(planRestrictions)) + + actions := svcCatClient.Actions() + Expect(actions[0].Matches("create", "clusterservicebrokers")).To(BeTrue()) + objectFromRequest := actions[0].(testing.CreateActionImpl).Object.(*v1beta1.ClusterServiceBroker) + Expect(objectFromRequest.ObjectMeta.Name).To(Equal(brokerName)) + Expect(objectFromRequest.Spec.URL).To(Equal(url)) + Expect(objectFromRequest.Spec.AuthInfo.Basic.SecretRef.Name).To(Equal(basicSecret)) + Expect(objectFromRequest.Spec.CABundle).To(Equal([]byte("foo\n"))) + Expect(objectFromRequest.Spec.InsecureSkipTLSVerify).To(BeTrue()) + Expect(objectFromRequest.Spec.RelistBehavior).To(Equal(relistBehavior)) + Expect(objectFromRequest.Spec.RelistDuration).To(Equal(relistDuration)) + Expect(objectFromRequest.Spec.CatalogRestrictions.ServicePlan).To(Equal(planRestrictions)) + }) + It("creates a broker with a bearer secret", func() { + brokerName := "potato_broker" + url := "http://potato.com" + namespace := "potatonamespace" + bearerSecret := "potatobearersecret" + opts := &RegisterOptions{ + Namespace: namespace, + BearerSecret: bearerSecret, + } + + broker, err := sdk.Register(brokerName, url, opts) Expect(err).NotTo(HaveOccurred()) Expect(broker).NotTo(BeNil()) @@ -162,6 +213,7 @@ var _ = Describe("Broker", func() { objectFromRequest := actions[0].(testing.CreateActionImpl).Object.(*v1beta1.ClusterServiceBroker) Expect(objectFromRequest.ObjectMeta.Name).To(Equal(brokerName)) Expect(objectFromRequest.Spec.URL).To(Equal(url)) + Expect(objectFromRequest.Spec.AuthInfo.Bearer.SecretRef.Name).To(Equal(bearerSecret)) }) It("Bubbles up errors", func() { errorMessage := "error provisioning broker" @@ -173,7 +225,7 @@ var _ = Describe("Broker", func() { }) sdk.ServiceCatalogClient = badClient - broker, err := sdk.Register(brokerName, url) + broker, err := sdk.Register(brokerName, url, &RegisterOptions{}) Expect(broker).To(BeNil()) Expect(err).To(HaveOccurred()) diff --git a/pkg/svcat/service-catalog/options.go b/pkg/svcat/service-catalog/options.go index d8c32b7f043..be6ecd22377 100644 --- a/pkg/svcat/service-catalog/options.go +++ b/pkg/svcat/service-catalog/options.go @@ -16,7 +16,25 @@ limitations under the License. package servicecatalog +import ( + "github.com/kubernetes-incubator/service-catalog/pkg/apis/servicecatalog/v1beta1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + // FilterOptions allows for optional filtering fields to be passed to `Retrieve` methods. type FilterOptions struct { ClassID string } + +// RegisterOptions allows for passing of optional fields to the broker Register method. +type RegisterOptions struct { + BasicSecret string + BearerSecret string + CAFile string + ClassRestrictions []string + Namespace string + PlanRestrictions []string + RelistBehavior v1beta1.ServiceBrokerRelistBehavior + RelistDuration *metav1.Duration + SkipTLS bool +} diff --git a/pkg/svcat/service-catalog/sdk.go b/pkg/svcat/service-catalog/sdk.go index 70098e48fce..5b2432eb473 100644 --- a/pkg/svcat/service-catalog/sdk.go +++ b/pkg/svcat/service-catalog/sdk.go @@ -48,7 +48,7 @@ type SvcatClient interface { RetrieveBrokers() ([]apiv1beta1.ClusterServiceBroker, error) RetrieveBroker(string) (*apiv1beta1.ClusterServiceBroker, error) RetrieveBrokerByClass(*apiv1beta1.ClusterServiceClass) (*apiv1beta1.ClusterServiceBroker, error) - Register(string, string) (*apiv1beta1.ClusterServiceBroker, error) + Register(string, string, *RegisterOptions) (*apiv1beta1.ClusterServiceBroker, error) Sync(string, int) error RetrieveClasses(ScopeOptions) ([]Class, error) diff --git a/pkg/svcat/service-catalog/service-catalogfakes/fake_svcat_client.go b/pkg/svcat/service-catalog/service-catalogfakes/fake_svcat_client.go index 7547c77f6ee..65d7cf5f647 100644 --- a/pkg/svcat/service-catalog/service-catalogfakes/fake_svcat_client.go +++ b/pkg/svcat/service-catalog/service-catalogfakes/fake_svcat_client.go @@ -232,11 +232,12 @@ type FakeSvcatClient struct { result1 *apiv1beta1.ClusterServiceBroker result2 error } - RegisterStub func(string, string) (*apiv1beta1.ClusterServiceBroker, error) + RegisterStub func(string, string, *servicecatalog.RegisterOptions) (*apiv1beta1.ClusterServiceBroker, error) registerMutex sync.RWMutex registerArgsForCall []struct { arg1 string arg2 string + arg3 *servicecatalog.RegisterOptions } registerReturns struct { result1 *apiv1beta1.ClusterServiceBroker @@ -1344,17 +1345,18 @@ func (fake *FakeSvcatClient) RetrieveBrokerByClassReturnsOnCall(i int, result1 * }{result1, result2} } -func (fake *FakeSvcatClient) Register(arg1 string, arg2 string) (*apiv1beta1.ClusterServiceBroker, error) { +func (fake *FakeSvcatClient) Register(arg1 string, arg2 string, arg3 *servicecatalog.RegisterOptions) (*apiv1beta1.ClusterServiceBroker, error) { fake.registerMutex.Lock() ret, specificReturn := fake.registerReturnsOnCall[len(fake.registerArgsForCall)] fake.registerArgsForCall = append(fake.registerArgsForCall, struct { arg1 string arg2 string - }{arg1, arg2}) - fake.recordInvocation("Register", []interface{}{arg1, arg2}) + arg3 *servicecatalog.RegisterOptions + }{arg1, arg2, arg3}) + fake.recordInvocation("Register", []interface{}{arg1, arg2, arg3}) fake.registerMutex.Unlock() if fake.RegisterStub != nil { - return fake.RegisterStub(arg1, arg2) + return fake.RegisterStub(arg1, arg2, arg3) } if specificReturn { return ret.result1, ret.result2 @@ -1368,10 +1370,10 @@ func (fake *FakeSvcatClient) RegisterCallCount() int { return len(fake.registerArgsForCall) } -func (fake *FakeSvcatClient) RegisterArgsForCall(i int) (string, string) { +func (fake *FakeSvcatClient) RegisterArgsForCall(i int) (string, string, *servicecatalog.RegisterOptions) { fake.registerMutex.RLock() defer fake.registerMutex.RUnlock() - return fake.registerArgsForCall[i].arg1, fake.registerArgsForCall[i].arg2 + return fake.registerArgsForCall[i].arg1, fake.registerArgsForCall[i].arg2, fake.registerArgsForCall[i].arg3 } func (fake *FakeSvcatClient) RegisterReturns(result1 *apiv1beta1.ClusterServiceBroker, result2 error) {