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 }