github.com/arunkumar7540/cli@v6.45.0+incompatible/integration/helpers/service_broker.go (about)

     1  package helpers
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"net/http"
     7  	"strings"
     8  
     9  	"io/ioutil"
    10  
    11  	. "github.com/onsi/gomega"
    12  	. "github.com/onsi/gomega/gbytes"
    13  	. "github.com/onsi/gomega/gexec"
    14  )
    15  
    16  const (
    17  	DefaultMemoryLimit = "256M"
    18  	DefaultDiskLimit   = "1G"
    19  )
    20  
    21  // PlanSchemas represent the broker-provided list of actions that can be taken on
    22  // instances of a given service plan.
    23  type PlanSchemas struct {
    24  	ServiceInstance struct {
    25  		Create struct {
    26  			Parameters map[string]interface{} `json:"parameters"`
    27  		} `json:"create"`
    28  		Update struct {
    29  			Parameters map[string]interface{} `json:"parameters"`
    30  		} `json:"update"`
    31  	} `json:"service_instance"`
    32  	ServiceBinding struct {
    33  		Create struct {
    34  			Parameters map[string]interface{} `json:"parameters"`
    35  		} `json:"create"`
    36  	} `json:"service_binding"`
    37  }
    38  
    39  // Plan represents the broker-provided specification for instances of a service plan.
    40  type Plan struct {
    41  	Name    string      `json:"name"`
    42  	ID      string      `json:"id"`
    43  	Schemas PlanSchemas `json:"schemas"`
    44  }
    45  
    46  // ServiceBroker represents a service broker conforming to the OSB API.
    47  type ServiceBroker struct {
    48  	Name       string
    49  	Path       string
    50  	AppsDomain string
    51  	Service    struct {
    52  		Name            string `json:"name"`
    53  		ID              string `json:"id"`
    54  		Bindable        bool   `json:"bindable"`
    55  		Requires        string `json:"-"`
    56  		DashboardClient struct {
    57  			ID          string `json:"id"`
    58  			Secret      string `json:"secret"`
    59  			RedirectUri string `json:"redirect_uri"`
    60  		}
    61  	}
    62  	SyncPlans              []Plan
    63  	AsyncPlans             []Plan
    64  	MaintenanceInfoVersion string
    65  }
    66  
    67  // NewServiceBroker constructs a new ServiceBroker with given attributes. planName will be used
    68  // to create a synchronous service plan on the broker.
    69  func NewServiceBroker(name, path, appsDomain, serviceName, planName string) ServiceBroker {
    70  	b := ServiceBroker{}
    71  	b.Path = path
    72  	b.Name = name
    73  	b.AppsDomain = appsDomain
    74  	b.Service.Name = serviceName
    75  	b.Service.ID = RandomName()
    76  	b.Service.Bindable = true
    77  	b.Service.Requires = `[]`
    78  	b.SyncPlans = []Plan{
    79  		{Name: planName, ID: RandomName()},
    80  		{Name: RandomName(), ID: RandomName()},
    81  	}
    82  	b.AsyncPlans = []Plan{
    83  		{Name: RandomName(), ID: RandomName()},
    84  		{Name: RandomName(), ID: RandomName()},
    85  		{Name: RandomName(), ID: RandomName()}, // accepts_incomplete = true
    86  	}
    87  	b.Service.DashboardClient.ID = RandomName()
    88  	b.Service.DashboardClient.Secret = RandomName()
    89  	b.Service.DashboardClient.RedirectUri = RandomName()
    90  	b.MaintenanceInfoVersion = "1.2.3"
    91  	return b
    92  }
    93  
    94  // NewAsynchServiceBroker constructs a new ServiceBroker with given attributes. planName will be used
    95  // to create an asynchronous service plan on the broker.
    96  func NewAsynchServiceBroker(name, path, appsDomain, serviceName, planName string) ServiceBroker {
    97  	b := ServiceBroker{}
    98  	b.Path = path
    99  	b.Name = name
   100  	b.AppsDomain = appsDomain
   101  	b.Service.Name = serviceName
   102  	b.Service.ID = RandomName()
   103  	b.Service.Bindable = true
   104  	b.Service.Requires = `[]`
   105  	b.SyncPlans = []Plan{
   106  		{Name: RandomName(), ID: RandomName()},
   107  		{Name: RandomName(), ID: RandomName()},
   108  	}
   109  	b.AsyncPlans = []Plan{
   110  		{Name: RandomName(), ID: RandomName()},
   111  		{Name: RandomName(), ID: RandomName()},
   112  		{Name: planName, ID: RandomName()}, // accepts_incomplete = true
   113  	}
   114  	b.Service.DashboardClient.ID = RandomName()
   115  	b.Service.DashboardClient.Secret = RandomName()
   116  	b.Service.DashboardClient.RedirectUri = RandomName()
   117  	b.MaintenanceInfoVersion = "1.2.3"
   118  	return b
   119  }
   120  
   121  // Push pushes the service broker as an app and maps a route to it.
   122  func (b ServiceBroker) Push() {
   123  	Eventually(CF(
   124  		"push", b.Name,
   125  		"--no-start",
   126  		"-m", DefaultMemoryLimit,
   127  		"-p", b.Path,
   128  		"--no-route",
   129  	)).Should(Exit(0))
   130  
   131  	Eventually(CF(
   132  		"map-route",
   133  		b.Name,
   134  		b.AppsDomain,
   135  		"--hostname", b.Name,
   136  	)).Should(Exit(0))
   137  
   138  	Eventually(CF("start", b.Name)).Should(Exit(0))
   139  }
   140  
   141  // Configure makes a service broker shareable (or not).
   142  func (b ServiceBroker) Configure(shareable bool) {
   143  	body := strings.NewReader(b.ToJSON(shareable))
   144  	req, err := http.NewRequest("POST", b.URL("/config"), body)
   145  	Expect(err).ToNot(HaveOccurred())
   146  	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
   147  
   148  	resp, err := http.DefaultClient.Do(req)
   149  	Expect(err).ToNot(HaveOccurred())
   150  	Expect(resp.StatusCode).To(Equal(http.StatusOK))
   151  	defer resp.Body.Close()
   152  }
   153  
   154  func (b ServiceBroker) UpdateMaintenanceInfo(version string) {
   155  	b.MaintenanceInfoVersion = version
   156  	b.Configure(true)
   157  	b.Update()
   158  }
   159  
   160  // Create creates a service broker with 'cf create-service-broker' and asserts that it exists.
   161  func (b ServiceBroker) Create() {
   162  	Eventually(CF("create-service-broker", b.Name, "username", "password", b.URL())).Should(Exit(0))
   163  	Eventually(CF("service-brokers")).Should(And(Exit(0), Say(b.Name)))
   164  }
   165  
   166  // Update updates a service broker with 'cf update-service-broker' and asserts that it has been updated.
   167  func (b ServiceBroker) Update() {
   168  	Eventually(CF("update-service-broker", b.Name, "username", "password", b.URL())).Should(Exit(0))
   169  	Eventually(CF("service-brokers")).Should(And(Exit(0), Say(b.Name)))
   170  }
   171  
   172  // Delete deletes a service broker with 'cf delete-service-broker' and asserts that it has been deleted.
   173  func (b ServiceBroker) Delete() {
   174  	Eventually(CF("delete-service-broker", b.Name, "-f")).Should(Exit(0))
   175  	Eventually(CF("service-brokers")).Should(And(Exit(0), Not(Say(b.Name))))
   176  }
   177  
   178  // Destroy purges a service broker with 'cf purge-service-offering'.
   179  func (b ServiceBroker) Destroy() {
   180  	Eventually(CF("purge-service-offering", b.Service.Name, "-b", b.Name, "-f")).Should(Exit(0))
   181  	b.Delete()
   182  	Eventually(CF("delete", b.Name, "-f", "-r")).Should(Exit(0))
   183  }
   184  
   185  func (b ServiceBroker) URL(paths ...string) string {
   186  	return fmt.Sprintf("http://%s.%s%s", b.Name, b.AppsDomain, strings.Join(paths, ""))
   187  }
   188  
   189  func (b ServiceBroker) ToJSON(shareable bool) string {
   190  	bytes, err := ioutil.ReadFile(NewAssets().ServiceBroker + "/broker_config.json")
   191  	Expect(err).To(BeNil())
   192  
   193  	planSchema, err := json.Marshal(b.SyncPlans[0].Schemas)
   194  	Expect(err).To(BeNil())
   195  
   196  	replacer := strings.NewReplacer(
   197  		"<fake-service>", b.Service.Name,
   198  		"<fake-service-guid>", b.Service.ID,
   199  		"<sso-test>", b.Service.DashboardClient.ID,
   200  		"<sso-secret>", b.Service.DashboardClient.Secret,
   201  		"<sso-redirect-uri>", b.Service.DashboardClient.RedirectUri,
   202  		"<fake-plan>", b.SyncPlans[0].Name,
   203  		"<fake-plan-guid>", b.SyncPlans[0].ID,
   204  		"<fake-plan-2>", b.SyncPlans[1].Name,
   205  		"<fake-plan-2-guid>", b.SyncPlans[1].ID,
   206  		"<fake-async-plan>", b.AsyncPlans[0].Name,
   207  		"<fake-async-plan-guid>", b.AsyncPlans[0].ID,
   208  		"<fake-async-plan-2>", b.AsyncPlans[1].Name,
   209  		"<fake-async-plan-2-guid>", b.AsyncPlans[1].ID,
   210  		"<fake-async-plan-3>", b.AsyncPlans[2].Name,
   211  		"<fake-async-plan-3-guid>", b.AsyncPlans[2].ID,
   212  		"\"<fake-plan-schema>\"", string(planSchema),
   213  		"\"<shareable-service>\"", fmt.Sprintf("%t", shareable),
   214  		"\"<bindable>\"", fmt.Sprintf("%t", b.Service.Bindable),
   215  		"\"<requires>\"", b.Service.Requires,
   216  		"<fake-maintenance-info-version>", b.MaintenanceInfoVersion,
   217  	)
   218  
   219  	return replacer.Replace(string(bytes))
   220  }
   221  
   222  // CreateBroker creates a new shareable broker which provides the user specified service plan to a foundation.
   223  func CreateBroker(domain, serviceName, planName string) ServiceBroker {
   224  	broker := NewServiceBroker(NewServiceBrokerName(), NewAssets().ServiceBroker, domain, serviceName, planName)
   225  	broker.Push()
   226  	broker.Configure(true)
   227  	broker.Create()
   228  
   229  	return broker
   230  }
   231  
   232  // CreateAsyncBroker creates a new shareable broker which provides the user specified service plan to a foundation.
   233  func CreateAsyncBroker(domain, serviceName, planName string) ServiceBroker {
   234  	broker := NewAsynchServiceBroker(NewServiceBrokerName(), NewAssets().ServiceBroker, domain, serviceName, planName)
   235  	broker.Push()
   236  	broker.Configure(true)
   237  	broker.Create()
   238  
   239  	return broker
   240  }
   241  
   242  // Assets wraps a path to a service broker asset
   243  type Assets struct {
   244  	ServiceBroker string
   245  }
   246  
   247  // NewAssets creates a new Assets struct which wraps a relative path to the included service broker asset
   248  func NewAssets() Assets {
   249  	return Assets{
   250  		ServiceBroker: "../../assets/service_broker",
   251  	}
   252  }