Skip to content

Commit 9e4a1a7

Browse files
committed
minor improvements to create service
add tests for create service
1 parent 147da7c commit 9e4a1a7

File tree

4 files changed

+307
-42
lines changed

4 files changed

+307
-42
lines changed

cmd/mobile/main.go

+6
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ import (
2323

2424
"path/filepath"
2525

26+
"log"
27+
2628
m "github.com/aerogear/mobile-cli/pkg/client/mobile/clientset/versioned"
2729
sc "github.com/aerogear/mobile-cli/pkg/client/servicecatalog/clientset/versioned"
2830
"github.com/aerogear/mobile-cli/pkg/cmd"
@@ -98,6 +100,10 @@ func main() {
98100
}
99101

100102
if err := rootCmd.Execute(); err != nil {
103+
// as using pkg/errors lets allow the full stack to be seen if needed
104+
if os.Getenv("MCP_DEBUG") == "true" {
105+
log.Fatalf("error: %+v", err)
106+
}
101107
os.Exit(1)
102108
}
103109
}

pkg/cmd/services.go

+97-42
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ func (sc *ServicesCmd) ListServicesCmd() *cobra.Command {
8989
return err
9090
}
9191

92-
params := &instanceCreateParams{}
92+
params := &InstanceCreateParams{}
9393
if err := json.Unmarshal(clusterServicePlan.Spec.ServiceInstanceCreateParameterSchema.Raw, &params); err != nil {
9494
return err
9595
}
@@ -124,7 +124,7 @@ func findServiceClassByName(scClient versioned.Interface, name string) (*v1beta1
124124
return nil, err
125125
}
126126
if mobileServices == nil || len(mobileServices.Items) == 0 {
127-
return nil, errors.New("failed to find and service classes for " + name)
127+
return nil, errors.New("failed to find serviceclass with name: " + name)
128128
}
129129

130130
for _, item := range mobileServices.Items {
@@ -137,11 +137,12 @@ func findServiceClassByName(scClient versioned.Interface, name string) (*v1beta1
137137
return &item, nil
138138
}
139139
}
140-
return nil, nil
140+
return nil, errors.New("failed to find serviceclass with name: " + name)
141141

142142
}
143143

144144
func findServicePlanByNameAndClass(scClient versioned.Interface, planName, serviceClassName string) (*v1beta1.ClusterServicePlan, error) {
145+
145146
plans, err := scClient.ServicecatalogV1beta1().ClusterServicePlans().List(metav1.ListOptions{})
146147
if err != nil {
147148
return nil, err
@@ -152,10 +153,31 @@ func findServicePlanByNameAndClass(scClient versioned.Interface, planName, servi
152153
}
153154
}
154155

155-
return nil, nil
156+
return nil, errors.New("failed to find serviceplan with associated with the serviceclass " + serviceClassName)
157+
}
158+
159+
func requiredParam(instParams InstanceCreateParams, key string) bool {
160+
for _, r := range instParams.Required {
161+
if r == key {
162+
return true
163+
}
164+
}
165+
return false
166+
}
167+
168+
func parseParams(keyVals []string) (map[string]string, error) {
169+
params := map[string]string{}
170+
for _, p := range keyVals {
171+
kv := strings.Split(p, "=")
172+
if len(kv) != 2 {
173+
return nil, NewIncorrectParameterFormat("key value pairs are needed failed to find one: " + p)
174+
}
175+
params[strings.TrimSpace(kv[0])] = kv[1]
176+
}
177+
return params, nil
156178
}
157179

158-
type instanceCreateParams struct {
180+
type InstanceCreateParams struct {
159181
AdditionalProperties bool `json:"additionalProperties"`
160182
Properties map[string]map[string]interface{} `json:"properties"`
161183
Required []string `json:"required"`
@@ -166,10 +188,16 @@ func (sc *ServicesCmd) CreateServiceInstanceCmd() *cobra.Command {
166188
cmd := &cobra.Command{
167189
Use: "serviceinstance <serviceName>",
168190
Short: `create a running instance of the given service`,
191+
Long: `Create service instance, allows you to provison an availble service to your namespace.
192+
To see which services are available, first list them using the "get services" command from this tool.
193+
Once you have selected a service, take note of its name then run:
194+
195+
create serviceinstance <selectedService>`,
169196
RunE: func(cmd *cobra.Command, args []string) error {
170197
if len(args) != 1 {
171198
return errors.New("expected the name of a service to provision")
172199
}
200+
// find our serviceclass and plan
173201
serviceName := args[0]
174202

175203
ns, err := currentNamespace(cmd.Flags())
@@ -178,47 +206,66 @@ func (sc *ServicesCmd) CreateServiceInstanceCmd() *cobra.Command {
178206
}
179207

180208
clusterServiceClass, err := findServiceClassByName(sc.scClient, serviceName)
181-
if err != nil || clusterServiceClass == nil {
182-
msg := "failed to find a service class associated with that name "
183-
if err != nil {
184-
msg += err.Error()
185-
}
186-
return errors.New(msg)
209+
if err != nil {
210+
return errors.WithStack(err)
187211
}
188212
clusterServicePlan, err := findServicePlanByNameAndClass(sc.scClient, "default", clusterServiceClass.Name)
189213
if err != nil {
190-
return err
214+
return errors.WithStack(err)
191215
}
192-
193-
if clusterServicePlan == nil {
194-
return errors.New("failed to find service plan with name default for service " + serviceName)
216+
// handle the params
217+
params, err := cmd.Flags().GetStringArray("params")
218+
if err != nil {
219+
return errors.WithStack(err)
195220
}
196-
197-
params := &instanceCreateParams{}
198-
199-
if err := json.Unmarshal(clusterServicePlan.Spec.ServiceInstanceCreateParameterSchema.Raw, params); err != nil {
200-
return err
221+
parsedParams, err := parseParams(params)
222+
if err != nil {
223+
return errors.WithStack(err)
224+
}
225+
instParams := &InstanceCreateParams{}
226+
if err := json.Unmarshal(clusterServicePlan.Spec.ServiceInstanceCreateParameterSchema.Raw, instParams); err != nil {
227+
return errors.WithStack(err)
201228
}
202-
scanner := bufio.NewScanner(os.Stdin)
203-
for k, v := range params.Properties {
204-
fmt.Printf("Set value for %v, default value: %v", k, v["default"])
205-
scanner.Scan()
206-
//
207-
val := scanner.Text()
208-
if val == "" {
209-
val = v["default"].(string)
229+
230+
if len(parsedParams) > 0 {
231+
for k, v := range instParams.Properties {
232+
defaultVal := v["default"]
233+
if pVal, ok := parsedParams[k]; !ok && requiredParam(*instParams, k) || requiredParam(*instParams, k) && pVal == "" {
234+
if defaultVal != nil {
235+
//use default
236+
v["value"] = defaultVal
237+
continue
238+
}
239+
return errors.New(fmt.Sprintf("missing required parameter %s", k))
240+
}
241+
v["value"] = parsedParams[k]
242+
instParams.Properties[k] = v
243+
}
244+
} else {
245+
246+
scanner := bufio.NewScanner(os.Stdin)
247+
for k, v := range instParams.Properties {
248+
questionFormat := "Set value for %s [default value: %s required: %v]"
249+
250+
fmt.Println(fmt.Sprintf(questionFormat, k, v["default"], requiredParam(*instParams, k)))
251+
scanner.Scan()
252+
//
253+
val := scanner.Text()
254+
if val == "" {
255+
val = v["default"].(string)
256+
}
257+
v["value"] = val
258+
instParams.Properties[k] = v
259+
fmt.Println("set value for " + k + " to : " + val)
210260
}
211-
v["value"] = val
212-
params.Properties[k] = v
213-
fmt.Println("set value for " + k + " to : " + val)
214261
}
215262

216263
validServiceName := clusterServiceClass.Spec.ExternalName
217264
sid := uuid.NewV4().String()
218265
extMeta := clusterServiceClass.Spec.ExternalMetadata.Raw
219266
var extServiceClass ExternalServiceMetaData
220267
if err := json.Unmarshal(extMeta, &extServiceClass); err != nil {
221-
return err
268+
return errors.WithStack(err)
222269
}
223270

224271
si := v1beta1.ServiceInstance{
@@ -251,7 +298,7 @@ func (sc *ServicesCmd) CreateServiceInstanceCmd() *cobra.Command {
251298
},
252299
}
253300
if _, err := sc.scClient.ServicecatalogV1beta1().ServiceInstances(ns).Create(&si); err != nil {
254-
return err
301+
return errors.WithStack(err)
255302
}
256303

257304
pSecret := v1.Secret{
@@ -262,38 +309,45 @@ func (sc *ServicesCmd) CreateServiceInstanceCmd() *cobra.Command {
262309
pSecret.Data = map[string][]byte{}
263310
parameters := map[string]string{}
264311

265-
for k, v := range params.Properties {
266-
parameters[k] = v["value"].(string)
312+
for k, v := range instParams.Properties {
313+
if v, ok := v["value"]; ok && v != nil {
314+
parameters[k] = v.(string)
315+
}
267316
}
268317
secretData, err := json.Marshal(parameters)
269318
if err != nil {
270-
return err
319+
return errors.WithStack(err)
271320
}
272321
pSecret.Data["parameters"] = secretData
273322
if _, err := sc.k8Client.CoreV1().Secrets(ns).Create(&pSecret); err != nil {
274-
return err
323+
return errors.WithStack(err)
275324
}
325+
276326
noWait, err := cmd.PersistentFlags().GetBool("no-wait")
277327
if err != nil {
278-
return err
328+
return errors.WithStack(err)
279329
}
280330
if noWait {
281331
return nil
282332
}
283333
w, err := sc.scClient.ServicecatalogV1beta1().ServiceInstances(ns).Watch(metav1.ListOptions{LabelSelector: "id=" + sid})
284334
if err != nil {
285-
return err
335+
return errors.WithStack(err)
286336
}
287337
for u := range w.ResultChan() {
338+
o := u.Object.(*v1beta1.ServiceInstance)
288339
switch u.Type {
340+
case watch.Error:
341+
w.Stop()
342+
return errors.New("unexpected error watching ServiceInstance " + err.Error())
289343
case watch.Modified:
290-
o := u.Object.(*v1beta1.ServiceInstance)
344+
291345
lastOp := o.Status.LastOperation
292346
if nil != lastOp {
293-
//fmt.Println("last operation " + *lastOp)
347+
fmt.Println("last operation: " + *lastOp)
294348
}
295349
for _, c := range o.Status.Conditions {
296-
fmt.Println(c.Message)
350+
fmt.Println("status: " + c.Message)
297351
if c.Type == "Ready" && c.Status == "True" {
298352
w.Stop()
299353
}
@@ -305,6 +359,7 @@ func (sc *ServicesCmd) CreateServiceInstanceCmd() *cobra.Command {
305359
},
306360
}
307361
cmd.PersistentFlags().Bool("no-wait", false, "--no-wait will cause the command to exit immediately instead of waiting for the service to be provisioned")
362+
cmd.PersistentFlags().StringArrayP("params", "p", []string{}, "set the parameters needed by the template: -p PARAM1=val -p PARAM2=val2")
308363
return cmd
309364
}
310365

0 commit comments

Comments
 (0)